2011-01-28 23 views
12

¿Cómo podría fusionar dos hashes que no dan como resultado claves nuevas, lo que significa que la fusión fusionaría las claves que existen en ambos hash?Cómo combinar dos hash sin claves nuevas

Por ejemplo, quiero lo siguiente:

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

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

Estoy buscando una manera muy limpia de hacer esto como mi implementación actual es bastante desordenado.

+0

Esto es como una intersección hash. ¿Qué quiere que suceda con los pares clave/valor con diferentes valores? Por ejemplo: h = {: foo => "value1"}; j = {: foo => "value2",: extra => "value"} –

+0

@Ron Gejman - Solo quiero echarlos. Pero has despertado mi interés. ¿Hay algún método hash/enumerable que devuelva dos hashes (uno con las claves duplicadas y otro con las sobras)? – elmt

+0

No, pero es fácil usar algo similar a la respuesta de DigitalRoss. Solo guárdelo en dos hashes diferentes: uno para los partidos y otro para los que no coinciden. –

Respuesta

14

Podría quitar las llaves que no estaban en el primer hash a partir de la segunda almohadilla, y luego fusionar:

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

A diferencia de mi alternativa editada de salida, esto es seguro si decide cambiar a un merge! o update.

+0

(eliminé mi voto, y lo cambié a un voto popular. Me confundí acerca de 'fusionar') –

+0

Esto da una advertencia en mi máquina-Hash.select toma en un bloque con dos argumentos (| k, v |). –

+1

Oh, vaya, escribo Ruby 1.9. –

7

La respuesta de Yjerem funciona en Ruby 1.9, pero no en 1.8.x. En 1.8.x, el método Hash#select devuelve una matriz. Hash#reject devuelve un hash.

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

Si desea mantener sólo pares de valores clave que tienen valores idénticos, se puede hacer esto:

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

El caso extremo hay Nils. Si va a guardar Nils en su Hash entonces usted tiene que hacer esto:

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

Gracias por su solución 1.8 Ron Gejman. – elmt

+0

Sí. Es compatible también con 1.9. –

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

o

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

o (probablemente el mejor, pero no es técnicamente una sola expresión) ...

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

Si está usando el acto ivesupport (parte de rieles), se puede tomar ventaja de 2 métodos adicionales en Hash:

  • Hash#slice toma las teclas deseadas como argumentos separados (no una matriz de claves) y devuelve un nuevo hash con sólo las teclas que solicitó para.
  • Hash#except toma los mismos argumentos que slice, pero devuelve un nuevo hash con claves que no estaban en los argumentos.

Primera ActiveSupport carga:

require 'active_support/core_ext' 

Combinar sólo las entradas de j cuyas claves ya están en h (es decir,modificar, pero no agregue cualquiera o eliminar entradas en h):

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

Ejemplo:

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} 

Obtener las sobras de j que no estaban en h:

j.except(*h.keys) 

Bonificación:

Si quieres verdadera intersección, lo que significa que quiere un resultado que sólo se dispone de teclas que se encuentran en común entre los 2 valores hash, hacer esto:

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

Ejemplo:

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} 

y sobras de h que weren 't en j:

h.except(*j.keys) 

también puede que quiera usar ActiveSupport de HashWithIndifferentAccess si quieres cadena & símbolo de acceso a clave para ser considerado equivalente.

Tenga en cuenta que ninguno de los ejemplos anteriores cambian los valores hash originales; nuevos hashes son devueltos en su lugar.

-1

La forma más personalizada de hacer esto es:

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

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


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

Aquí la clave "foo" en el segundo hash es decisivo, los "foo" en la primera hash.But si desea mantener el valor antiguo es decir, barra o si desea mantener el nuevo valor, es decir, "baz"? Puede hacer algo como esto:

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

La pregunta pide una intersección de las teclas. El resultado debería ser {: foo => "baz"}, no {"foo" => "baz", "extra" => "valor"} – AndrewKS