わかりましたので、ここに契約があります、私はこれに対する解決策を見つけるために長年グーグルで探してきましたが、そこには多くのものがありますが、彼らは私が探している仕事をしていないようです。
基本的に私はこのような構造の配列を持っています
["item 1", "item 2", "item 3", "item 4"]
これをハッシュに変換して、次のようにします
{ "item 1" => "item 2", "item 3" => "item 4" }
つまり、「偶数」インデックスにあるアイテムがキーであり、「奇数」インデックスにあるアイテムが値です。
これをきれいに行う方法はありますか?総当たり方式では、すべての偶数インデックスを個別の配列に引き出し、それらをループして値を追加するだけだと思います。
a = ["item 1", "item 2", "item 3", "item 4"]
h = Hash[*a] # => { "item 1" => "item 2", "item 3" => "item 4" }
それでおしまい。 *
はsplat演算子と呼ばれます。
@Mike Lewisごとに1つの警告(コメント):「これに非常に注意してください。Rubyはスタック上のスプラットを展開します。これを大規模なデータセットで行う場合は、スタックを吹き飛ばしてください。」
そのため、ほとんどの一般的な使用例では、この方法は優れていますが、大量のデータを変換する場合は別の方法を使用してください。たとえば、@ŁukaszNiemier(これもコメントにあります)は、大規模なデータセットに対してこのメソッドを提供します。
h = Hash[a.each_slice(2).to_a]
Ruby 2.1.0では、配列にto_h
メソッドが導入されました。これは、元の配列がキーと値のペアの配列で構成される場合に必要なことを行います。 http://www.Ruby-doc.org/core-2.1.0/ Array.html#method-i-to_h 。
[[:foo, :bar], [1, 2]].to_h
# => {:foo => :bar, 1 => 2}
配列の値にHash.[]
を使用するだけです。例えば:
arr = [1,2,3,4]
Hash[*arr] #=> gives {1 => 2, 3 => 4}
または、[key, value]
配列の配列がある場合は、次のことができます。
[[1, 2], [3, 4]].inject({}) do |r, s|
r.merge!({s[0] => s[1]})
end # => { 1 => 2, 3 => 4 }
これは私がこれをグーグルで探しているときに探していたものです:
[{a: 1}, {b: 2}].reduce({}) { |h, v| h.merge v } => {:a=>1, :b=>2}
Enumerator
には Enumerable
が含まれます。 2.1
なので、Enumerable
にもメソッド #to_h
があります。そのため、次のように記述できます。
a = ["item 1", "item 2", "item 3", "item 4"]
a.each_slice(2).to_h
# => {"item 1"=>"item 2", "item 3"=>"item 4"}
#each_slice
ブロックなしではEnumerator
が得られるため、上記の説明に従って、Enumerator
オブジェクトで#to_h
メソッドを呼び出すことができます。
単一の配列に対して、このように試すことができます
irb(main):019:0> a = ["item 1", "item 2", "item 3", "item 4"]
=> ["item 1", "item 2", "item 3", "item 4"]
irb(main):020:0> Hash[*a]
=> {"item 1"=>"item 2", "item 3"=>"item 4"}
配列の配列
irb(main):022:0> a = [[1, 2], [3, 4]]
=> [[1, 2], [3, 4]]
irb(main):023:0> Hash[*a.flatten]
=> {1=>2, 3=>4}
a = ["item 1", "item 2", "item 3", "item 4"]
Hash[ a.each_slice( 2 ).map { |e| e } ]
または、Hash[ ... ]
が嫌いな場合:
a.each_slice( 2 ).each_with_object Hash.new do |(k, v), h| h[k] = v end
または、壊れた関数型プログラミングの怠け者の場合:
h = a.lazy.each_slice( 2 ).tap { |a|
break Hash.new { |h, k| h[k] = a.find { |e, _| e == k }[1] }
}
#=> {}
h["item 1"] #=> "item 2"
h["item 3"] #=> "item 4"
すべての回答は、開始配列が一意であることを前提としています。 OPは、重複したエントリを持つ配列を処理する方法を指定しませんでした。これにより、キーが重複します。
見てみましょう:
a = ["item 1", "item 2", "item 3", "item 4", "item 1", "item 5"]
Bij item 1 => item 2
がオーバーライドされると、item 1 => item 5
ペアは失われます。
Hash[*a]
=> {"item 1"=>"item 5", "item 3"=>"item 4"}
reduce(&:merge!)
を含むすべてのメソッドは、同じ削除をもたらします。
ただし、これはまさにあなたが期待していることかもしれません。しかし、他の場合では、代わりにArray
の値を使用して結果を取得する必要があります。
{"item 1"=>["item 2", "item 5"], "item 3"=>["item 4"]}
単純な方法は、ヘルパー変数、デフォルト値を持つハッシュを作成し、それをループで埋めることです:
result = Hash.new {|hash, k| hash[k] = [] } # Hash.new with block defines unique defaults.
a.each_slice(2) {|k,v| result[k] << v }
a
=> {"item 1"=>["item 2", "item 5"], "item 3"=>["item 4"]}
assoc
とreduce
を使用して上記の1行を実行することは可能かもしれませんが、それを推論して読むことははるかに難しくなります。