2016-12-08 36 views
6

mam hash:Wiele sub-mieszań z jednego 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"} 

Jaki jest najlepszy sposób, aby uzyskać następujące podgrupy skrótów:

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

chcę je pogrupowane według klucza, na podstawie wyrażeń regularnych /^a_(\d+)/. Będę miał pięćdziesiąt par klucz/wartość w oryginalnym haszu, więc coś dynamicznego będzie działało najlepiej, jeśli ktokolwiek ma jakieś sugestie.

+3

Tak szybki wybór pierwszej udzielonej odpowiedzi może zniechęcić do innych odpowiedzi i zwarcia tych, którzy wciąż pracują nad odpowiedziami. Nie ma pośpiechu. Wielu tutaj czeka co najmniej kilka godzin przed wyborem odpowiedzi, niektórzy czekają znacznie dłużej. –

+1

OK, dzięki za poradę, jestem tu nowy :) –

+0

W rzeczywistości niektórzy czekają miesiące! Inni nigdy tego nie robią! LOL –

Odpowiedz

7

Jeżeli obawiasz się tylko o średnim komponentu można użyć group_by aby dostać się większość drogi tam:

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

Ostatnim krokiem jest wyodrębnianie zgrupowane listy i łącząc te z powrotem do wymaganych mieszań .

+1

Wygląda na to, czego szuka OP. Może też sprawić, że będzie bardziej lakoniczny, jeśli OP jest zainteresowany tym rodzajem rzeczy 'hash.group_by {| k, _ | k.split ('_') [1]} .values.map (&: to_h) ' – Damon

+0

Dokładnie tego, czego szukałem, dzięki! –

4

kod

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

Przykład

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

Objaśnienie

Kroki są następujące.

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({})> 

Pierwszy element tego wyliczający są generowane i przesyłane do bloku, a blokami zmiennych są obliczane przy użyciu równolegle zadania.

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

i wykonywane jest obliczanie bloku.

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

więc teraz

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

Następny wartość enum jest teraz generowane i przekazywane do bloku, oraz następujące obliczenia są wykonywane.

(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"} 

Po czterech pozostałych elementów enum są przekazywane do bloku następuje nie jest zwracana.

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

Ostatnim krokiem jest po prostu wyodrębnienie wartości.

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