1

次のデータ構造変換を行う「Rubyist」の方法は何ですか:

私は持っている

    着信 = [ {:日付 => 20090501, :幅 => 2},
                 {:日付 => 20090501, :高さ => 7},
                 {:日付 => 20090501, :深さ => 3},
                 {:日付 => 20090502, :幅 => 4},
                 {:日付 => 20090502, :高さ => 6},
                 {:日付 => 20090502, :深さ => 2},
               ]

そして、これらを:dateまでに折りたたんで、最終的に

    送信 = [ {:日付 => 20090501、:幅 => 2、:高さ => 7、:深さ => 3}、
                 {:日付 => 20090502, :幅 => 4, :高さ => 6, :深さ => 2},
               ]

列が各行で同じ順序になっている場合、配列の配列も最後のステップで問題ありません。また、重要なことに、すべてのハッシュ キーが事前にわかっているわけではありません (つまり、:width、:height、または :depth はわかりません。:cats、:dogs、および :hamsters の可能性があります)。

4

4 に答える 4

8

Ruby 1.8.7 または Ruby 1.9+ を使用している場合、次のコードは適切に読み取れます。

incoming.group_by{|hash| hash[:date]}.map do |_, hashes| 
  hashes.reduce(:merge)
end

ブロック属性のアンダースコア (_、ハッシュ) は、その特定の属性を必要としない/気にしないことを示します。

#reduce は #inject のエイリアスで、コレクションを 1 つのアイテムに縮小するために使用されます。Ruby の新しいバージョンでは、 reductionを行うために使用されるメソッドの名前であるシンボルも受け入れます。

2 番目の項目を引数として、コレクション内の最初の項目でメソッドを呼び出すことから始めます。次に、3 番目の項目を引数として結果に対してメソッドを再度呼び出し、項目がなくなるまで繰り返します。

[1, 3, 2, 2].reduce(:+) => [4, 2, 2] => [6, 2] => 8
于 2009-06-13T19:10:40.193 に答える
2

ここにワンライナーがあります:)

incoming.inject({}){ |o,i| o[i[:date]]||=[];o[i[:date]]<<i;o}.map{|a| a[1].inject(){|o,i| o.merge(i)}}

しかし実際には、以前の投稿の方が明確であり、より高速である可能性もあります。

編集:少し最適化:

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)}}
于 2009-06-13T15:18:00.083 に答える
2

簡潔な解決策:

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]}

ここで唯一注意が必要なのは Hash コンストラクターです。これにより、存在しないキーにアクセスしたときに呼び出されるブロックを指定できます。そこで、Hash に空の Hash を作成させて、見つけた値で更新できるようにします。次に、日付をハッシュ キーとして使用し、ハッシュ値を日付で並べ替えて変換します。

于 2009-06-13T15:38:08.990 に答える
0

これを試して:

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
于 2009-06-13T15:07:51.463 に答える