慣用ルビー:データ構造変換
-
13-09-2019 - |
質問
次のようなデータ構造変換を行うための「Rubyist」方法は何ます:
私が持っている
incoming = [ {:date => 20090501, :width => 2}, {:date => 20090501, :height => 7}, {:date => 20090501, :depth => 3}, {:date => 20090502, :width => 4}, {:date => 20090502, :height => 6}, {:date => 20090502, :depth => 2}, ]
と私がすることで、これらを折りたたむしたい:
で終わるし、日付outgoing = [ {:date => 20090501, :width => 2, :height => 7, :depth => 3}, {:date => 20090502, :width => 4, :height => 6, :depth => 2}, ]
配列の配列はまた、最後のステップにおいて、列は、各行に同じ順序であることは、微細であろう。私は事前にすべてのハッシュキーを知らない。また、重要なのは、(:、幅:高さ、あるいは:つまり、私は知らない深さ - 彼らは次のようになります。猫:犬、そして:ハムスター)。
解決
次のコードがうまく読み取る1.9+ルビー1.8.7又はルビーを使用している場合
incoming.group_by{|hash| hash[:date]}.map do |_, hashes|
hashes.reduce(:merge)
end
ブロック属性でアンダースコア(_、ハッシュは)私たちは、その特定の属性を気に/必要がないことを示しています。
#reduceは、単一のアイテムに減らすのコレクションに使用される#injectの別名です。新しいRubyのバージョンでは、それはまた、の削減の操作を行うために使用されるメソッドの名前であるシンボルを、受け入れます。
これは、引数として2番目の項目に、コレクション内の最初の項目のメソッドを呼び出すことによって開始します。それ以上の項目が存在しなくなるまで、それは、次にように引数として3番目の項目と結果に再度メソッドを呼び出します。
[1, 3, 2, 2].reduce(:+) => [4, 2, 2] => [6, 2] => 8
他のヒント
ここに1つのライナーです:)
incoming.inject({}){ |o,i| o[i[:date]]||=[];o[i[:date]]<<i;o}.map{|a| a[1].inject(){|o,i| o.merge(i)}}
しかし、実際には前の投稿は、より明確で、かつ速く過ぎるかもしれません。
EDIT:最適化のビットでます:
p incoming.inject(Hash.new{|h,k| h[k]=[]}){ |o,i| o[i[:date]]<<i;o}.map{|a| a[1].inject(){|o,i| o.merge(i)}}
簡潔な解決策ます:
incoming = [ {:date => 20090501, :width => 2},
{:date => 20090501, :height => 7},
{:date => 20090501, :depth => 3},
{:date => 20090502, :width => 4},
{:date => 20090502, :height => 6},
{:date => 20090502, :depth => 2},
]
temp = Hash.new {|hash,key| hash[key] = {}}
incoming.each {|row| temp[row[:date]].update(row)}
outgoing = temp.values.sort {|*rows| rows[0][:date] <=> rows[1][:date]}
ここでは、すべてのトリッキーだ唯一のことは、あなたが存在しないキーにアクセスすると呼ばれていますブロックを供給することを可能にするハッシュコンストラクタです。だから私は、私たちは私たちが探している値で更新するためにハッシュが空のハッシュを作成しています。その後、私はちょうど日付別のハッシュ値をソート、ハッシュキーとして日付を使用して、我々は変換しています。
これを試してください:
incoming = [ {:date => 20090501, :width => 2},
{:date => 20090501, :height => 7},
{:date => 20090501, :depth => 3},
{:date => 20090502, :width => 4},
{:date => 20090502, :height => 6},
{:date => 20090502, :depth => 2},
]
# Grouping by `:date`
temp = {}
incoming.each do |row|
if temp[row[:date]].nil?
temp[row[:date]] = []
end
temp[row[:date]] << row
end
# Merging it together
outcoming = []
temp.each_pair do |date, hashlist|
res = {}
hashlist.each do |hash|
res.merge!(hash)
end
outcoming << res
end
hash
-メンバーに関する情報については、このページを参照してください。
、あなたはギザギザの配列を使用する必要があります:
incoming = [ {:date => 20090501, :width => 2},
{:date => 20090501, :height => 7},
{:date => 20090501, :depth => 3},
{:date => 20090502, :width => 4},
{:date => 20090502, :height => 6},
{:date => 20090502, :depth => 2},
]
# Grouping by `:date`
temp = {}
incoming.each do |row|
if temp[row[:date]].nil?
temp[row[:date]] = []
end
key = row[:date]
row.delete :date
temp[key] << row
end
# Merging it together
outcoming = []
temp.each_pair do |date, hashlist|
res = [:date, date]
hashlist.each do |hash|
hash.each_pair {|key, value| res << [key, value] }
end
outcoming << res
end