2011-01-28 18 views
12

Jak mogę scalić dwa hashe, które nie dają nowych kluczy, co oznacza, że ​​scalenie scaliłoby klucze istniejące w obu hasach?Jak scalić dwa hashe bez nowych kluczy?

Na przykład, chcę następujące:

h = {:foo => "bar"} 
j = {:foo => "baz", :extra => "value"} 

puts h.merge(j) # {:foo => "baz"} 

szukam naprawdę czystą sposób to zrobić jak mój obecny realizacji jest dość niechlujny.

+0

To jest jak skrzyżowanie hash. Co chcesz zrobić z parami klucz/wartość o różnych wartościach? Na przykład: h = {: foo => "value1"}; j = {: foo => "value2",: extra => "value"} –

+0

@Ron Gejman - Po prostu chcę je wyrzucić. Ale wzbudziłeś moje zainteresowanie. Czy istnieje metoda hash/przeliczalna, która zwróci dwa hashe (jeden z duplikatami i drugi z resztkami)? – elmt

+0

Nie, ale łatwo można użyć czegoś podobnego do odpowiedzi DigitalRoss. Po prostu zapisz dwa różne skróty - jeden na mecze i jeden na nie. –

Odpowiedz

14

Można usunąć klucze, które nie były w pierwszej hash z drugiej hash, a następnie scalić:

h.merge j.select { |k| h.keys.include? k } 

przeciwieństwie do mojego redakcją-out alternatywa, to jest bezpieczne, jeśli zdecydujesz się zmienić go na merge! lub update.

+0

(usunąłem mój downwote i zmieniłem go na "Przegłos" o 'scaleniu') –

+0

Daje to ostrzeżenie na moim komputerze-Hash.select przyjmuje blok z dwoma argumentami (| k, v |). –

+1

Och, whoops, piszę Ruby 1.9. –

7

Odpowiedź Yjerem'a działa w Rubim 1.9, ale nie w 1.8.x. W wersji 1.8.x metoda Hash#select zwraca tablicę. Hash#reject zwraca skrót.

h.reject { |k,v| !j.keys.include? k } 

Jeśli chcesz zachować tylko par klucz-wartość, które mają identyczne wartości, można to zrobić:

h.reject { |k,v| j[k] != h[k] } 

Sprawa krawędź jest Nils. Jeśli przechowywania Nils w swojej Hash to trzeba to zrobić:

h.reject { |k,v| !j.has_key? k or j[k] != h[k] } 
+0

Dziękujemy za rozwiązanie 1,8 Ron Gejman. – elmt

+0

Tak. Jest również kompatybilny z 1.9. –

0
[h].inject({}) { |m,e| e.merge(j) { |k,o,n| m[k] = n }; m} 

lub

[{}].inject(h) { |m,e| m.merge(j) { |k,o,n| e[k] = n }; e} 

lub (prawdopodobnie najlepsza, ale technicznie nie pojedynczy wyraz) ...

t = {}; h.merge(j) { |k,o,n| t[k] = n }; t 
8

Jeśli używasz aktu ivesupport (część szyn), można skorzystać z 2 dodatkowymi metodami na Hash:

  • Hash#slice wykonuje żądane klawisze odsunięte (nie tablicę kluczy) i zwraca nowy hash z zaledwie klawiszy Pytałeś dla.
  • Hash#except przyjmuje te same argumenty co slice, ale zwraca nowy skrót z kluczami, których nie ma w argumentach.

pierwsze ActiveSupport obciążenie:

require 'active_support/core_ext' 

Scal wpisy tylko z j których klucze są już h (tjmodyfikować, ale nie dodawać dowolne lub usunąć wpisy w h):

h.merge(j.slice(*h.keys)) 

Przykład:

ignore_new = ->(h, j) { h.merge(j.slice(* h.keys)) } 
ignore_new.({a: 1, b: 2, c: 3}, {b: 10, c: 11, d: 12}) 
# => {:a=>1, :b=>10, :c=>11} 

Get resztki z j, które nie były w h:

j.except(*h.keys) 

Bonus:

Jeśli chcesz prawdziwe skrzyżowanie, czyli chcesz rezultatu, który ma tylko klucze, które są wspólne między 2 mieszań, to zrobić:

h.merge(j).slice(* (h.keys & j.keys)) 

Przykład:

intersect = ->(h, j) { h.merge(j).slice(* (h.keys & j.keys)) } 
intersect.({a: 1, b: 2, c: 3}, {b: 10, c: 11, d: 12}) 
# => {:b=>10, :c=>11} 

i resztki z h że byłeś „tw j:

h.except(*j.keys) 

można również użyć ActiveSupport na HashWithIndifferentAccess jeśli chcesz ciąg & symbol klucza dostępu, aby można go było uznać za równoważny.

Należy zauważyć, że żaden z powyższych przykładów nie zmienia oryginalnych skrótów; zamiast tego zwracane są nowe skróty.

-1

Im bardziej dostosowany sposobem osiągnięcia tego celu jest:

h = {"foo"=> "bar"} 

j = {"foo" => "baz", "extra" => "value"} 


k = h.merge(j) 
result: {"foo"=>"baz", "extra"=>"value"} 

Oto klucz „foo” w drugim hash jest przesłanianie „foo” w pierwszym hash.But jeśli chcesz zachować starą wartość IE pasek lub jeśli chcesz zachować nową wartość, np. "baz"? Możesz zrobić coś takiego:

k = h.merge(j){|key, old, new| old} 
result: {"foo"=>"bar", "extra"=>"value"} 


k = h.merge(j){|key, old, new| new} 

result: {"foo"=>"baz", "extra"=>"value"} 
+0

Pytanie prosi o przecięcie klawiszy. Wynik powinien być {: foo => "baz"}, a nie {"foo" => "baz", "dodatkowy" => "wartość"} – AndrewKS