概要
Rubyにて、配列の要素が重複しているかどうかを検証したい。例えば[1,2,3]ならtrueを、[1,2,3,2]ならfalseを戻すように。
Arrayの標準メソッドにそれらしいものがあると思っていたが、どうやら内容なので自前で作ることに。
前提
ruby2.2.2で動作確認
普通にメソッドを実装する
def uniq?(array) uniq_check = {} array.each do |v| return false if uniq_check.key? v uniq_check[v] = true end return true end
array.uniq.size == array.size とかでも良かったけど、パフォーマンス的にこっちのほうが良さげ?
配列を引数にして利用する。
[2] pry(main)> uniq?([1,2,3]) => true [3] pry(main)> uniq?([1,2,3,2]) => false
Arrayクラスにメソッドを追加する
前項の普通にメソッドを実装するのも良いけど、使い方がRubyっぽくないので、Arrayクラスにメソッドを追加する形で再実装する。
class Array ## # 要素が全てユニークであるかを評価 # [1,2,3].uniq? - true # [1,2,3,2].uniq? - false def uniq? uniq_check = {} each do |v| return false if uniq_check.key? v uniq_check[v] = true end return true end end
Arrayのメソッドとしてuniq?を呼べるようになる
[2] pry(main)> [1,2,3].uniq? => true [3] pry(main)> [1,2,3,2].uniq? => false
オマケ 重複してる要素を取得する
あわせて、[1,2,3,2,3]なら[2,3]を、[1,1,1,1]なら[1]を取得するようなメソッドも欲しかったのでまとめて実装した。
class Array def duplicates uniq_check = {} dups = {} each do |v| dups[v] = true if uniq_check.key? v uniq_check[v] = true end dups.keys end end
良い感じに抜き出せた
[2] pry(main)> [1,2,3,2,3].duplicates => [2, 3] [3] pry(main)> [1,1,1,1,1].duplicates => [1]
オマケ rspecによる単体テスト
Array#uniq?とArray#duplicatesのrspecによる単体テストも書いた。
describe Array do describe 'uniq?' do subject { array.uniq? } context '[1, 2, 3]' do let(:array) { [1, 2, 3] } it { is_expected.to be true } end context '[1, 2, 3, 2]' do let(:array) { [1, 2, 3, 2] } it { is_expected.to be false } end context '[]' do let(:array) { [] } it { is_expected.to be true } end end describe 'duplicates' do subject { array.duplicates } context '[1, 2, 3]' do let(:array) { [1, 2, 3] } it { is_expected.to eq [] } end context '[1, 2, 3, 2, 3]' do let(:array) { [1, 2, 3, 2, 3] } it { is_expected.to eq [2, 3] } end context '[1,2,1]' do let(:array) { [1, 2, 1] } it { is_expected.to eq [1] } end context '[1, 1, 1, 1, 1]' do let(:array) { [1, 1, 1, 1, 1] } it { is_expected.to eq [1] } end end end
テスト結果
Array uniq? [1, 2, 3] should equal true [1, 2, 3, 2] should equal false [] should equal true duplicates [1, 2, 3] should eq [] [1, 2, 3, 2, 3] should eq [2, 3] [1,2,1] should eq [1] [1, 1, 1, 1, 1] should eq [1] Finished in 0.01665 seconds (files took 4.48 seconds to load) 7 examples, 0 failures