Rubyの新機能のために、私はこの問題の実体であるものも含めて、この問題に対する別のアプローチについて議論しました。
あなたは、配列
arr = [[:dog, "fido"], [:car, "audi"], [:cat, "lucy"], [:dog, "diva"], [:cat, "bo"]]
に与えられたハッシュに
{ :dog=>["fido", "diva"], :car=>["audi"], :cat=>["lucy", "bo"] }
まずソリューションを作成することを希望していると仮定したタスク
h = {}
arr.each do |k,v|
h[k] = [] unless h.key?(k)
h[k] << v
end
h #=> {:dog=>["fido", "diva"], :car=>["audi"], :cat=>["lucy", "bo"]}
これはかなり簡単です。
h = {}
arr.each { |k,v| (h[k] ||= []) << v }
h #=> {:dog=>["fido", "diva"], :car=>["audi"], :cat=>["lucy", "bo"]}
Rubyが見(h[k] ||= []) << v
彼女が最初に行うことはh
がない場合
(h[k] = h[k] || []) << v
に展開です:
第2の解決策は、
ルビーのようなよりは書くことですキーがありませんk
、h[k] #=> nil
、したがって式beco MES
(h[k] = []) << v
右側h[k]
がHash#[]を採用し、一方、等式の左側にh[k]
は、方法Hash#[]=を使用するように
h[k] #=> [v]
注なる
(h[k] = nil || []) << v
。
この解決方法では、ハッシュ値のいずれもnil
に等しくないことが必要です。
第三の溶液
第三のアプローチは、ハッシュにデフォルト値を与えることです。ハッシュh
にキーk
がない場合、h[k]
がデフォルト値を返します。デフォルト値には2種類あります。空の配列は、Hash::new
に引数として渡された場合Hash::new
に引数としてデフォルト値を渡す
、その値はデフォルト値となる:
a = []
a.object_id
#=> 70339916855860
g = Hash.new(a)
#=> {}
g[k]
戻る[]
h
キーはk
ではありません。 (ただし、ハッシュは変更されません)。この構造は重要な用途を持っていますが、ここでは不適切です。理由を知るために、我々は:cat
と:dog
の値は両方とも同じオブジェクト、空の配列に等しく設定されているためです
x = g[:cat] << "bo"
#=> ["bo"]
y = g[:dog] << "diva"
#=> ["bo", "diva"]
x #=> ["bo", "diva"]
書くと仮定します。私たちは、object_id
Sを調べることによって、これを見ることができます:
x.object_id
#=> 70339916855860
y.object_id
#=> 70339916855860
がデフォルト値デフォルト値の二番目の形式は、ブロックの計算を実行することである
を返すブロックHash::new
を与えます。私たちはブロックでハッシュを定義する場合:
h = Hash.new { |h,k| h[key] = [] }
そしてh
場合は、キーk
、h[k]
この場合、空の配列には、ブロックによって返された値に等しく設定されていません。ブロック変数h
は、新しく作成された空のハッシュです。これは私たちが
h = Hash.new { |h,k| h[k] = [] }
arr.each { |k,v| h[k] << v }
h #=> {:dog=>["fido", "diva"], :car=>["audi"], :cat=>["lucy", "bo"]}
ブロックに渡される最初の要素はarr.first
であるように書くことができ、ブロック変数が
k, v = arr.first
#=> [:dog, "fido"]
k #=> :dog
v #=> "fido"
ブロック演算を評価することによって値が割り当てられしたがって
h[k] << v
#=> h[:dog] << "fido"
ありますh
は(まだ)キー:dog
を持っていないので、ブロックがトリガーされ、h[k]
equ空の配列を「FIDO」が付加されていることを[]
、次いでに対するAl、同様
h #=> { :dog=>["fido"] }
ように、arr
の次の二つの要素は、我々は
h #=> { :dog=>["fido"], :car=>["audi"], :cat=>["lucy"] }
とき次を有するブロックに渡された後に(第四)arr
の要素がブロックに渡され、私たちは
h[:dog] << "diva"
を評価したが、今h
は、鍵を持っているので、DEFA最後にarr
の最後の要素が処理されます。ハッシュ::ブロックで新しいを使用しているとき、私たちはこのような何かを書くことができ、
注:場合h[k]
はlaunch_missiles
の戻り値に等しく設定されるだろう
h = Hash.new { launch_missiles("any time now") }
します。言い換えれば、何でもブロック内で行うことができます。
さらにルビーのような
最後に、
h = Hash.new { |h,k| h[k] = [] }
arr.each { |k,v| h[k] << v }
h #=> {:dog=>["fido", "diva"], :car=>["audi"], :cat=>["lucy", "bo"]}
を書くよりルビーのような方法がEnumerable#each_with_objectを使用することです:
2行のコードを排除 arr.each_with_object(Hash.new { |h,k| h[k] = [] }) { |k,v| h[k] << v }
#=> {:dog=>["fido", "diva"], :car=>["audi"], :cat=>["lucy", "bo"]}
。
どちらが最適ですか?
私は個人的に、第2および第3の解決策には無関心です。両方とも実際に使用されます。
ヒント:ブロックに 'puts'を追加すると、*正確に*が実行されたときにすぐに表示されます。 –