LoginSignup
5
4

More than 5 years have passed since last update.

1つのキーに複数の値が対応して且つそれぞれの値が重複しているハッシュのキーと値を入れ替えたい時のメソッド(Ruby)

Posted at

実例からっ

タイトルがわかりにくいのでやりたいことを実例で示します。

#もとのHash
 {"akan"=>["10", "201"], "areha"=>["201"], "okashi"=>["303", "201", "10"]}
#入れ替え後
=> {"10"=>["akan", "okashi"], "201"=>["akan", "areha", "okashi"], "303"=>["okashi"]}

上記のように1つのキーに複数の値がぶら下がっていて,その値同士が重複しているとします。上の例では,"akan"=>"201","areha"=>"201","okashi"=>"201"と"akan"=>"10","okashi"=>"10"が重複しています。
複数対複数であるということを認識しながら,これらのキーと値を入れ替えると,"入れ替え後"のようになります。ちょいと探したところすぐにいいメソッドが見つからなかったので,メソッドを作りました。

メソッド

def safe_invert_d_hash(orig_hash)
orig_array = []
orig_hash.each{|elem|
if elem[1].length != 1
 elem[1].each{|youso|
    orig_array << [youso,elem[0]]
    }
else
        orig_array << [elem[1].join(""),elem[0]]
end
} 
result = Hash.new{|h,key| h[key] = []}
    orig_array.each{|key,value|
        result[key] << value
    }
result
end

最初,配列(orig_array)を作って,そこに一対一になるようにデータを入れていきます。この時にキーと値の順序を交換しています。複数の値は1つ1つ取り出しています。
ここまでの処理で上記の例だと,[["10", "akan"], ["201", "akan"], ["201", "areha"], ["303", "okashi"], ["201", "okashi"], ["10", "okashi"]]となっています。
次に先ほど作った配列から,ハッシュ(result)を作って,最初の要素をkey,後の要素をvalueとすればおしまいです。Have fun! というか,もっといい方法(修正)があったら教えて下さい。#あと,値が配列の形じゃないとこのメソッド使えないです。ごめんなさい。

実行結果

irb(main):538:0* h
=> {"akan"=>["10", "201"], "areha"=>["201"], "okashi"=>["303", "201", "10"]}
irb(main):539:0> safe_invert_d_hash(h)
=> {"10"=>["akan", "okashi"], "201"=>["akan", "areha", "okashi"], "303"=>["okashi"]}

あ,最初の例そのままですね。ええ。

Reference

Rubyレシピブック 第2版 268の技 
こちらのsafe_invertを参照しています。

最後にきっかけ

同義語の対応付けの処理をしていて,多(by DB_A)対多(by DB_B)のIDを関連付ける必要がありました。片方のデータベース(DB_A)からしか,対応データが取得できない状況だったが,取得したいのは,(DB_B)からの対応付けだったのでこんなのを作りました。しかし,あれだ,例が,"あかん,あれは,おかし"だったのは,あれですな,あれ。あとデータ量多い時にはRubyじゃないほうがいいですよね,うん。

5
4
3

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
4