2011-01-01 20 views
20

Aquí está mi situación. Tengo 2 matricesRuby fusionando dos matrices en una

@names = ["Tom", "Harry", "John"] 

@emails = ["[email protected]", "[email protected]", "[email protected]"] 

quiero combinar estos dos en algunos Array/Hash llamados @list por lo que a continuación se pueden repetir en mi opinión algo como esto:

<% @list.each do |item| %> 
<%= item.name %><br> 
<%= item.email %><br> 
<% end %> 

estoy teniendo problemas para entender cómo Puedo lograr este objetivo. ¿Alguna idea?

Respuesta

46
@names = ["Tom", "Harry", "John"] 
@emails = ["[email protected]", "[email protected]", "[email protected]"] 

@list = @names.zip(@emails) 
#=> [["Tom", "[email protected]"], ["Harry", "[email protected]"], ["John", "[email protected]"]] 

@list.each do |name,email| 
    # When a block is passed an array you can automatically "destructure" 
    # the array parts into named variables. Yay for Ruby! 
    p "#{name} <#{email}>" 
end 
#=> "Tom <[email protected]>" 
#=> "Harry <[email protected]>" 
#=> "John <[email protected]>" 

@urls = ["yahoo.com", "ebay.com", "google.com"] 

# Zipping multiple arrays together 
@names.zip(@emails, @urls).each do |name,email,url| 
    p "#{name} <#{email}> :: #{url}" 
end 
#=> "Tom <[email protected]> :: yahoo.com" 
#=> "Harry <[email protected]> :: ebay.com" 
#=> "John <[email protected]> :: google.com" 
+4

Aha! Entonces * ¡esto * es para lo que 'zip' es! De alguna manera, nunca entró realmente en mi caja de herramientas estándar. Bonito. +1 – Matchu

+0

Si esta solución sigue siendo aplicable, agregué otra variable de instancia llamada @urls = ["yahoo.com", "ebay.com", "google.com"]. – lou1221

+0

@ lou1221 Sí; vea la respuesta actualizada arriba. 'Array # zip' puede tomar una cantidad arbitraria de argumentos. – Phrogz

3

Puede utilizar zip para comprimir juntos los dos arrays y luego map para crear Item objetos a partir de los nombres-email-pares. Asumiendo que tiene una clase Item cuyos métodos initialize acepta un hash, el código se vería así:

@list = @names.zip(@emails).map do |name, email| 
    Item.new(:name => name, :email => email) 
end 
7
Hash[*names.zip(emails).flatten] 

Esto le dará un hash con el nombre => correo electrónico.

+1

Funciona para esta situación, pero los lectores futuros deben tener cuidado: no es una solución general, ya que si cualquiera de los 'nombres' o' correos electrónicos' eran matrices que contenían matrices, 'flatten' se ejecutaría de forma recursiva. – Matchu

+5

En Ruby 1.9 puede simplemente hacer: 'Hash [nombres.zip (correos electrónicos)]' – Phrogz

+2

aplanar (1) evitará la recursión, si lo desea. –

15

sólo para ser diferente:

[@names, @emails, @urls].transpose.each do |name, email, url| 
    # . . . 
end 

Esto es similar a lo que hace Array#zip excepto que en este caso no habrá ningún relleno nula de filas cortas; si falta algo, se generará una excepción.

+5

La sugerencia sobre la transposición es excelente. Gracias por publicar este – lou1221

+1

Estaba buscando el 'zip (* arrays)' de Python. ¡Eso es todo! – Droogans