2016-12-08 2 views
6

У меня есть хэш:несколько суб-хэшей из одного хэша

hash = {"a_1_a" => "1", "a_1_b" => "2", "a_1_c" => "3", "a_2_a" => "3", 
     "a_2_b" => "4", "a_2_c" => "4"} 

Какой самый лучший способ, чтобы получить следующие подвиды хэшей:

[{"a_1_a" => "1", "a_1_b" => "2", "a_1_c" => "3"}, 
{"a_2_a" => "3", "a_2_b" => "4", "a_2_c" => "4"}] 

Я хочу, чтобы они сгруппированы по ключу, на основе regexp /^a_(\d+)/. У меня будет 50+ пар ключ/значение в исходном хеше, поэтому что-то динамическое будет работать лучше всего, если у кого есть какие-то предложения.

+3

Такой быстрый выбор предлагаемого первого ответа может препятствовать другим ответам и короткому замыканию тех, кто все еще работает над ответами. Там нет спешки. Многие здесь ждут по крайней мере пару часов, прежде чем выбрать ответ, некоторые ждут гораздо дольше, чем это. –

+1

Хорошо, спасибо за совет, я здесь новый :) –

+0

На самом деле, некоторые ждут месяцы! Другие никогда не делают! LOL –

ответ

7

Если вы беспокоитесь только о среднем компоненты вы можете использовать group_by, чтобы вы большая часть пути туда:

hash.group_by do |k,v| 
    k.split('_')[1] 
end.values.map do |list| 
    Hash[list] 
end 

# => [{"a_1_a"=>"1", "a_1_b"=>"2", "a_1_c"=>"3"}, {"a_2_a"=>"3", "a_2_b"=>"4", "a_2_c"=>"4"}] 

Последний шаг является извлечением сгруппированных списков и объединение их обратно в необходимых хэш ,

+1

Это похоже на то, что ищет OP. Может также сделать его немного более кратким, если OP заинтересован в такого рода вещах. 'hash.group_by {| k, _ | k.split ('_') [1]} .values.map (&: to_h) ' – Damon

+0

Точно, что я искал, спасибо! –

4

код

def partition_hash(hash) 
    hash.each_with_object({}) do |(k,v), h| 
    key = k[/(?<=_).+(?=_)/] 
    h[key] = (h[key] || {}).merge(k=>v) 
    end.values 
end 

Пример

hash = {"a_1_a"=>"1", "a_1_b"=>"2", "a_1_c"=>"3", "a_2_a"=>"3", "a_2_b"=>"4", "a_2_c"=>"4"} 
partition_hash(hash) 
    #=> [{"a_1_a"=>"1", "a_1_b"=>"2", "a_1_c"=>"3"}, 
    # {"a_2_a"=>"3", "a_2_b"=>"4", "a_2_c"=>"4"}] 

Объяснение

шаги заключаются в следующем.

enum = hash.each_with_object({}) 
    #=> #<Enumerator: {"a_1_a"=>"1", "a_1_b"=>"2", "a_1_c"=>"3", "a_2_a"=>"3", 
    #     "a_2_b"=>"4", "a_2_c"=>"4"}:each_with_object({})> 

Первый элемент этого перечислителем генерируется и передается в блок, и блок-переменные вычисляются с использованием параллельного назначения.

(k,v), h = enum.next 
    #=> [["a_1_a", "1"], {}] 
k #=> "a_1_a" 
v #=> "1" 
h #=> {} 

и расчет блока выполнен.

key = k[/(?<=_).+(?=_)/] 
    #=> "1" 
h[key] = (h[key] || {}).merge(k=>v) 
    #=> h["1"] = (h["1"] || {}).merge("a_1_a"=>"1") 
    #=> h["1"] = (nil || {}).merge("a_1_a"=>"1") 
    #=> h["1"] = {}.merge("a_1_a"=>"1") 
    #=> h["1"] = {"a_1_a"=>"1"} 

так что теперь

h #=> {"1"=>{"a_1_a"=>"1"}} 

Следующее значение enum теперь генерируется и передается в блок, и следующие расчеты.

(k,v), h = enum.next 
    #=> [["a_1_b", "2"], {"1"=>{"a_1_a"=>"1"}}] 
k #=> "a_1_b" 
v #=> "2" 
h #=> {"1"=>{"a_1_a"=>"1"}} 

key = k[/(?<=_).+(?=_)/] 
    #=> "1" 
h[key] = (h[key] || {}).merge(k=>v) 
    #=> h["1"] = (h["1"] || {}).merge("a_1_b"=>"2") 
    #=> h["1"] = ({"a_1_a"=>"1"}} || {}).merge("a_1_b"=>"2") 
    #=> h["1"] = {"a_1_a"=>"1"}}.merge("a_1_b"=>"2") 
    #=> h["1"] = {"a_1_a"=>"1", "a_1_b"=>"2"} 

После остальных четырех элементов enum были переданы в блок следующее уже возвращается.

h #=> {"1"=>{"a_1_a"=>"1", "a_1_b"=>"2", "a_1_c"=>"3"}, 
    # "2"=>{"a_2_a"=>"3", "a_2_b"=>"4", "a_2_c"=>"4"}} 

Последний шаг - просто извлечь значения.

h.values 
    #=> [{"a_1_a"=>"1", "a_1_b"=>"2", "a_1_c"=>"3"}, 
    # {"a_2_a"=>"3", "a_2_b"=>"4", "a_2_c"=>"4"}] 
Смежные вопросы