Мне больше нравится ответ @MarkThomas, но для скорости и эффективности памяти я предлагаю:
flatter = {}.tap{ |h| original.values.each{ |h2| h.merge!(h2) } }
Сравнительный анализ 200 000 итераций текущих ответов показывает, что это самый быстрый:
user system total real
Phrogz 0.710000 0.020000 0.730000 ( 0.728706)
Joshua Creek 0.830000 0.010000 0.840000 ( 0.830700)
Mark Thomas symbol 1.460000 0.020000 1.480000 ( 1.486463)
Mark Thomas to_proc 1.540000 0.030000 1.570000 ( 1.565354)
Tim Peters 1.650000 0.030000 1.680000 ( 1.678283)
Поскольку комментарий @ tokland - original.values.reduce(:update)
- изменяет исходный хеш, мы не можем сравнивать его напрямую с другими методами.Однако, если мы изменим все тесты, чтобы поместить дубликат первого хеша обратно в исходный каждую итерацию, ответ @ tokland станет самым быстрым, хотя и не таким быстрым, как мой:
user system total real
tokland's destroyer 0.760000 0.010000 0.770000 ( 0.772774)
Phrogz 1.020000 0.020000 1.040000 ( 1.034755)
Joshua Creek 1.060000 0.000000 1.060000 ( 1.063874)
Mark Thomas symbol 1.780000 0.040000 1.820000 ( 1.816909)
Mark Thomas to_proc 1.790000 0.030000 1.820000 ( 1.819014)
Tim Peters 1.800000 0.040000 1.840000 ( 1.827984)
Если вам нужноабсолютная скорость, и можно изменять исходные значения, используйте ответ @ tokland.Если вы сделаете это и хотите сохранить исходные необработанные хэши в целости и сохранности, то вы можете:
first_k,orig_v = original.each{ |k,v| break [k,v.dup] }
merged = original.values.reduce(:update)
original[first_k] = orig_v
Обратите внимание, что в заголовке вашего вопроса написано traverse ;если вы на самом деле не хотите объединять значения - если вы захотите дважды посетить дублированный ключ вместо последних выигрышей, - просто выполните:
original.values.each{ |h| h.each{ |k,v|
# hey, we're traversing inside!
} }