2016-12-11 2 views
3

でカウントのハッシュする要素のRubyの配列を変換します。私は、キーは、各内部配列のカウントしているハッシュを作成したいRubyで2次元配列を指定してインデックス

[ [1, 1, 1], 
    [1, 1], 
    [1, 1, 1, 1], 
    [1, 1] 
] 

をし、値は元の配列の添え字の配列であり、内部配列のサイズは特定の数です。結果ハッシュは次のようになります:

{ 2 => [1, 3], 3 => [0], 4 => [2] } 

これをRubyでどのように簡潔に表現していますか?私はHash.new([]).tap { |h| array.each_with_index { |a, i| h[a.length] << i } }に似たものを試していますが、結果として生じるハッシュは空です。

答えて

5

コードには2つの問題があります。最初はhが空であるとhキー2を持っていないので、あなたは、そう何のキーと値をデフォルト値を返さないので、この式は[] << 1 #=> [1]なるが、[1]はハッシュに添付されていないh[2]h[2] << 1、たとえば、書くときということですが加えられる。

書く必要があります。h[2] = h[2] << 1 です。その場合、コードはh #=> {3=>[0, 1, 2, 3], 2=>[0, 1, 2, 3], 4=>[0, 1, 2, 3]}を返します。残念ながら、それはまだ間違っています。これは、コードで2番目の問題を引き起こします。新しく作成したハッシュのデフォルト値を正しく定義していないからです。

h[3].object_id 
    #=> 70113420279440 
h[2].object_id 
    #=> 70113420279440 
h[4].object_id 
    #=> 70113420279440 

あはっは、すべての3つの値が同じオブジェクトであることを

最初のノート! hにキーkがない場合、newの引数[]h[k]によって返されます。問題は、同じ配列がすべてのキーkに返されるため、最初の新しいキーの空の配列にキーと値のペアを追加してから、2番目のキーと値のペアを追加することですそのと同じ次の新しいキーの配列など。ハッシュの定義方法については、以下を参照してください。

あなたのコードはうまく動作しますが、私は次のように書くことをお勧めします。

ハッシュの デフォルト値を計算するためにブロックを使用しています Hash::newの形(すなわち、ハッシュ hキー kを持っていないとき h[k]によって返された値)を使用し
arr = [ [1, 1, 1], [1, 1], [1, 1, 1, 1], [1, 1] ] 

arr.each_with_index.with_object(Hash.new {|h,k| h[k]=[]}) { |(a,i),h| 
    h[a.size] << i } 
    #=> {3=>[0], 2=>[1, 3], 4=>[2]} 

arr.each_with_index.with_object({}) { |(a,i),h| (h[a.size] ||= []) << i } 
    #=> {3=>[0], 2=>[1, 3], 4=>[2]} 

両方のは、以下の効果であります

もう1つの方法は、内側の配列ごとにインデックスを取得した後に配列サイズをグループ化することです(Enumerable#group_by)。

h = arr.each_with_index.group_by { |a,i| a.size } 
    #=> {3=>[[[1, 1, 1], 0]], 
    # 2=>[[[1, 1], 1], [[1, 1], 3]], 
    # 4=>[[[1, 1, 1, 1], 2]]} 
h.each_key { |k| h[k] = h[k].map(&:last) } 
    #=> {3=>[0], 2=>[1, 3], 4=>[2]} 

1発現h[2] = h[2] << 1=の左側にh[2]は、デフォルト値を返さない理由である、方法Hash#[]=Hash#[]を使用しています。代わりに、この式はh[2] ||= [] << 1と書くことができます。

+0

ああを与えるだろう。私は 'arr.with_object'を最初に試みて失敗しました。 – ybakos

+2

私の答えで使用したコードの臭いを避けて、ブロックからハッシュを宣言する、非常に便利な '#with_object'。もう一度感謝します。あなたのようなマスターから学ぶチャンスがあることは特権です。 –

+0

@ybakos 'with_object'はEnumeratorオブジェクトでのみ機能します。あるいは、Arrayクラスに 'with_object'メソッドが定義されていないと言うこともできます。 –

3
arry = [ [1, 1, 1], 
     [1, 1], 
     [1, 1, 1, 1], 
     [1, 1] 
     ] 

h = {} 
arry.each_with_index do |el,i| 
    c = el.count 
    h.has_key?(c) ? h[c] << i : h[c] = [i] 
end 

p h 

これには、それはあなたがそれをチェーン方法です、あなたに

{3=>[0], 2=>[1, 3], 4=>[2]} 
関連する問題