2011-03-02 27 views
49

Tengo dos matrices:Combinar dos matrices en Hash

members  = ["Matt Anderson", "Justin Biltonen", "Jordan Luff", "Jeremy London"] 
instruments = ["guitar, vocals", "guitar", "bass", "drums"] 

Lo que me gustaría hacer es combinar estos para que la estructura de datos resultante es un hash de este modo:

{"Matt Anderson"=>["guitar", "vocals"], "Justin Biltonen"=>"guitar", "Jordan Luff"=>"bass", "Jeremy London"=>"drums"} 

Tenga en cuenta que el valor de "Matt Anderson" ahora es una matriz en lugar de una cadena. ¿A todos los magos de Ruby les importa hacer esto?

Hash[*members.zip(instruments).flatten] los combina casi como yo quiero, sino lo que trata de convertir las "guitarras, voces" cadena en una matriz en primer lugar? Gracias.

+2

¿No hay una función de zip? –

+1

el '*' y '.flatten' en el ejemplo de la pregunta no son necesarios. 'Hash [members.zip (instruments)]' da el mismo resultado que 'Hash [* members.zip (instruments) .flatten]' – nohat

+1

Lo convertiría en '{..." Justin Biltonen "=> [" guitar "] ...}', ya que facilitará el trabajo más tarde, en cuyo caso map/zip/split/Hash dará una buena solución. –

Respuesta

44

Uso map y split para convertir las cuerdas del instrumento en matrices:

instruments.map {|i| i.include?(',') ? (i.split /, /) : i} 

A continuación, utilice Hash[] y zipmembers combinar con instruments:

Hash[members.zip(instruments.map {|i| i.include?(',') ? (i.split /, /) : i})] 

a GE t

{"Jeremy London"=>"drums", 
"Matt Anderson"=>["guitar", "vocals"], 
"Jordan Luff"=>"bass", 
"Justin Biltonen"=>"guitar"} 

Si no le importa si las listas de un solo tema son también matrices, puede utilizar esta solución más simple:

Hash[members.zip(instruments.map {|i| i.split /, /})] 

que le da esto:

{"Jeremy London"=>["drums"], 
"Matt Anderson"=>["guitar", "vocals"], 
"Jordan Luff"=>["bass"], 
"Justin Biltonen"=>["guitar"]} 
+0

+1 Pero no puedo imaginar para qué sirve su primera solución. ¿Por qué el hash devuelve una cadena o una matriz? Elegiría su segunda solución en cualquier momento. ("Steenslag" => []) – steenslag

+4

@steenslag es bueno para ser exactamente lo que la pregunta :-) – nohat

1
h = {} 
members.each_with_index do |el,ix| 
    h[el] = instruments[ix].include?(",") ? instruments[ix].split(",").to_a : instruments[ix] 
end 
h 
+0

En realidad, mi error es que necesita verificar si necesita la cadena para una sola entrada en lugar de una matriz que contiene una cadena – macarthy

0
h = {} 

members.each_with_index {|item, index| 
    h.store(item,instruments[index].split) 
} 
1
members.inject({}) { |m, e| t = instruments.delete_at(0).split(','); m[e] = t.size > 1 ? t : t[0]; m } 

Si no le importan las matrices de 1 elemento en el resultado, puede utilizar:

members.inject({}) { |m, e| m[e] = instruments.delete_at(0).split(','); m } 
86

Como se publicó en Rafe Kettler, usar zip es el camino a seguir.

Hash[members.zip(instruments)] 
+5

La solución más simple que he visto. –

+3

Esta respuesta es incorrecta. OP pidió '{" Matt Anderson "=> [" guitarra "," voces "], ...}', pero esta respuesta devuelve '{" Matt Anderson "=>" guitarra, voces ", ...}' – nohat

+0

¿Cómo se puede hacer lo mismo pero nombrando las teclas? es decir '{[: member => 'Jeremy London,: instrument =>' drums '], [: member =>' other guy ',: instrument =>' guitar '] ...' – kakubei

7

Ejemplo 01

k = ['a', 'b', 'c'] 
v = ['aa', 'bb'] 
h = {} 

k.zip(v) { |a,b| h[a.to_sym] = b } 
# => nil 

p h 
# => {:a=>"aa", :b=>"bb", :c=>nil} 

Ejemplo 02

k = ['a', 'b', 'c'] 
v = ['aa', 'bb', ['aaa','bbb']] 
h = {} 

k.zip(v) { |a,b| h[a.to_sym] = b } 
p h 
# => {:a=>"aa", :b=>"bb", :c=>["aaa", "bbb"]} 
+0

muy simple, gracias –

3

Este es el mejor y más limpio manera de hacer lo que quiera.

Hash[members.zip(instruments.map{|i| i.include?(',') ? i.split(',') : i})] 

Enjoy!