Это противоположно Превращение хэша массивов в массив хэшей в Ruby .
Элегантно и / или эффективно превращайте массив хэшей в хэш, где значениями являются массивы всех значений:
hs = [
{ a:1, b:2 },
{ a:3, c:4 },
{ b:5, d:6 }
]
collect_values( hs )
#=> { :a=>[1,3], :b=>[2,5], :c=>[4], :d=>[6] }
Этот краткий код почти работает, но не может создать массив, когда нет дубликатов :
def collect_values( hashes )
hashes.inject({}){ |a,b| a.merge(b){ |_,x,y| [*x,*y] } }
end
collect_values( hs )
#=> { :a=>[1,3], :b=>[2,5], :c=>4, :d=>6 }
Этот код работает, но можете ли вы написать лучшую версию?
def collect_values( hashes )
# Requires Ruby 1.8.7+ for Object#tap
Hash.new{ |h,k| h[k]=[] }.tap do |result|
hashes.each{ |h| h.each{ |k,v| result[k]<
Решения, которые работают только в Ruby 1.9, приемлемы, но должны быть отмечены как таковые.
Вот результаты тестирования различных ответов ниже ( и еще несколько моих),
[{: a => 1}, {: b => 2}, {: c => 3}, {: d => 4}, {: e => 5}, {: f => 6 }, {: g => 7}, ...]
один, где каждый хэш имеет один и тот же ключ, поэтому происходит максимальное слияние: [{: a => 1}, {: a => 2}, {: a => 3}, {: a => 4}, {: a => 5}, {: a => 6 }, {: a => 7}, ...]
[{: c => 1}, {: d => 1}, {: c => 2}, {: f => 1}, {: c => 1,: d => 1}, {: h => 1}, {: c => 3}, ...]
user system total real Phrogz 2a 0.577000 0.000000 0.577000 ( 0.576000) Phrogz 2b 0.624000 0.000000 0.624000 ( 0.620000) Glenn 1 0.640000 0.000000 0.640000 ( 0.641000) Phrogz 1 0.671000 0.000000 0.671000 ( 0.668000) Michael 1 0.702000 0.000000 0.702000 ( 0.700000) Michael 2 0.717000 0.000000 0.717000 ( 0.726000) Glenn 2 0.765000 0.000000 0.765000 ( 0.764000) fl00r 0.827000 0.000000 0.827000 ( 0.836000) sawa 0.874000 0.000000 0.874000 ( 0.868000) Tokland 1 0.873000 0.000000 0.873000 ( 0.876000) Tokland 2 1.077000 0.000000 1.077000 ( 1.073000) Phrogz 3 2.106000 0.093000 2.199000 ( 2.209000)
Самый быстрый код - это добавленный мной метод:
def collect_values(hashes)
{}.tap{ |r| hashes.each{ |h| h.each{ |k,v| (r[k]||=[]) << v } } }
end
Я принял " ответ Гленна Макдональда "поскольку он был конкурентоспособным с точки зрения скорости, достаточно кратким, но (что наиболее важно) потому, что он указывал на опасность использования хэша с самомодифицирующимся процессом по умолчанию для удобного построения, поскольку это может привести к плохим изменениям, когда пользователь индексирует это позже.
Наконец, вот код теста на случай, если вы захотите провести собственное сравнение:
require 'prime' # To generate the third hash
require 'facets' # For tokland1's map_by
AZSYMBOLS = (:a..:z).to_a
TESTS = {
'26 Distinct Hashes' => AZSYMBOLS.zip(1..26).map{|a| Hash[*a] },
'26 Same-Key Hashes' => ([:a]*26).zip(1..26).map{|a| Hash[*a] },
'26 Mixed-Keys Hashes' => (2..27).map do |i|
factors = i.prime_division.transpose
Hash[AZSYMBOLS.values_at(*factors.first).zip(factors.last)]
end
}
def phrogz1(hashes)
Hash.new{ |h,k| h[k]=[] }.tap do |result|
hashes.each{ |h| h.each{ |k,v| result[k]<