ホーム DoRuby rubyで配列から重複する値を抽出する方法を探した際に見つけたgroup_byメソッドが便利だった
rubyで配列から重複する値を抽出する方法を探した際に見つけたgroup_byメソッドが便利だった
 

rubyで配列から重複する値を抽出する方法を探した際に見つけたgroup_byメソッドが便利だった

この記事はアピリッツの技術ブログ「DoRuby」から移行した記事です。情報が古い可能性がありますのでご注意ください。

重複を排除するときは uniq ですが、重複を取り出すメソッドはない。 直接実行するメソッドはないけれど Array#group_byを使うと簡単にできる

参考:
・ Rubyで配列内の重複する値を抽出する方法
http://kiyotakakubo.hatenablog.com/entry/20110801/1312196444
・ rubyのgroup_byが便利
http://simanman.hatenablog.com/entry/2013/03/16/193552
・ instance method Enumerable#group_by
https://docs.ruby-lang.org/ja/latest/method/Enumerable/i/group_by.html

環境
ruby 2.4.1p111 (2017-03-22 revision 58053) [x86_64-darwin16]
irb 0.9.6(09/06/30)

実行例

  arr = [1, 2, 3, 2, 3, 4, 3, 4, 5, 4, 5, 6] # 配列を準備
  arr.group_by{|i| i}.reject{|k,v| v.one?}.keys # 魔法を使う
 => [2, 3, 4, 5]

Array#group_by
ブロックで渡した値をキーとした配列をハッシュにする。
arr.group_by{|i| i}
=> {1=>[1], 2=>[2, 2], 3=>[3, 3, 3], 4=>[4, 4, 4], 5=>[5, 5], 6=>[6]}

応用

・ カナ付きの名称を持つレコードを最初の文字でグルーピングする例

Something.all.to_a.group_by{ |product| product.name_kana.first}

・ 一行の文字列にいくつものデータを含んだ名前を持つデータをグルーピングする例

arr2 = %w(
  productcd1_skucode1_100
  productcd1_skucode2_200
  productcd2_skucode3_100
  productcd3_skucode3_150
) # 商品コード_SKUコード_値段のようなイメージ
arr2.group_by { |one_line_record| one_line_record.split('_').first } #商品コードで分けるみたいな

arr2.group_by { |one_line_record| one_line_record.split('_').last.to_i} #値段で分けるみたいな

重複する値を取り出すときの補足

  • Array#reject ブロックで渡した値が true を返す要素を除く
  • Array#one? 要素数が 1 あるかどうかを true / false で返す arr.group_by{|i| i}.reject{|k,v| v.one?} => {2=>[2, 2], 3=>[3, 3, 3], 4=>[4, 4, 4], 5=>[5, 5]}
  • Hash#keys ハッシュキーの配列を返す

付録

Arrayクラスに今回扱ったメソッドを追加するサンプル

class Array
  def ununiq
    group_by{|i| i}.reject{|k,v| v.one?}.keys
  end
end
 [1, 2, 3, 2, 3, 4, 3, 4, 5, 4, 5, 6].ununiq
記事を共有

最近人気な記事