Matriz a Hash Ruby


Bien, así que este es el trato, he estado buscando en Google durante siglos para encontrar una solución a esto y, si bien hay muchos por ahí, no parecen hacer el trabajo que estoy buscando.

Básicamente tengo una matriz estructurada como esta

["item 1", "item 2", "item 3", "item 4"] 

Quiero convertir esto en un Hash para que se vea así

{ "item 1" => "item 2", "item 3" => "item 4" }

Es decir, los elementos que están en los índices 'par' son las claves y los elementos en los índices 'impar' son los valores.

¿Alguna idea de cómo hacer esto limpiamente? Supongo que un bruto el método de fuerza sería simplemente extraer todos los índices pares en una matriz separada y luego hacer un bucle alrededor de ellos para agregar los valores.

Author: Max, 2010-10-27

8 answers

Uso to_h:

a = ["item 1", "item 2", "item 3", "item 4"]
h = a.to_h # => { "item 1" => "item 2", "item 3" => "item 4" }

Para la posteridad, a continuación está la respuesta para las versiones de ruby


a = ["item 1", "item 2", "item 3", "item 4"]
h = Hash[*a] # => { "item 1" => "item 2", "item 3" => "item 4" }

Eso es todo. El * se llama el operador splat.

Una advertencia por @Mike Lewis (en los comentarios): "Ten mucho cuidado con esto. Ruby expande splats en la pila. Si hace esto con un conjunto de datos grande, espere eliminar su pila."

Por lo tanto, para la mayoría de los casos de uso general, este método es excelente, pero use un método diferente si desea hacerlo la conversión en una gran cantidad de datos. Por ejemplo, @Łukasz Niemier (también en los comentarios) ofrece este método para grandes conjuntos de datos:

h = Hash[a.each_slice(2).to_a]
 335
Author: Ben Lee,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-10-03 03:56:01

Ruby 2.1.0 introdujo un método to_h en la matriz que hace lo que necesita si su matriz original consiste en matrices de pares clave-valor: http://www.ruby-doc.org/core-2.1.0/Array.html#method-i-to_h .

[[:foo, :bar], [1, 2]].to_h
# => {:foo => :bar, 1 => 2}
 91
Author: Jochem Schulenklopper,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-01-13 21:40:06

Simplemente use Hash.[] con los valores de la matriz. Por ejemplo:

arr = [1,2,3,4]
Hash[*arr] #=> gives {1 => 2, 3 => 4}
 24
Author: Chuck,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-06-01 20:38:27

O si tienes una matriz de [key, value] matrices, puedes hacer:

[[1, 2], [3, 4]].inject({}) do |r, s|
  r.merge!({s[0] => s[1]})
end # => { 1 => 2, 3 => 4 }
 23
Author: Erik Escobedo,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-12-11 06:42:01

Esto es lo que estaba buscando al googlear esto:

[{a: 1}, {b: 2}].reduce({}) { |h, v| h.merge v } => {:a=>1, :b=>2}

 8
Author: Karl Glaser,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-09-16 06:47:44

Enumerator incluye Enumerable. Desde 2.1, Enumerable también tiene un método #to_h. Por eso, podemos escribir :-

a = ["item 1", "item 2", "item 3", "item 4"]
a.each_slice(2).to_h
# => {"item 1"=>"item 2", "item 3"=>"item 4"}

Porque #each_slice sin bloque nos da Enumerator, y según la explicación anterior, podemos llamar al método #to_h en el objeto Enumerator.

 7
Author: Arup Rakshit,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-07-27 12:34:55
a = ["item 1", "item 2", "item 3", "item 4"]
Hash[ a.each_slice( 2 ).map { |e| e } ]

O, si odias Hash[ ... ]:

a.each_slice( 2 ).each_with_object Hash.new do |(k, v), h| h[k] = v end

O, si eres un fan perezoso de la programación funcional rota:

h = a.lazy.each_slice( 2 ).tap { |a|
  break Hash.new { |h, k| h[k] = a.find { |e, _| e == k }[1] }
}
#=> {}
h["item 1"] #=> "item 2"
h["item 3"] #=> "item 4"
 5
Author: Boris Stitnicky,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-06-01 20:29:43

Usted podría intentar así, para una sola matriz

irb(main):019:0> a = ["item 1", "item 2", "item 3", "item 4"]
  => ["item 1", "item 2", "item 3", "item 4"]
irb(main):020:0> Hash[*a]
  => {"item 1"=>"item 2", "item 3"=>"item 4"}

Para array de array

irb(main):022:0> a = [[1, 2], [3, 4]]
  => [[1, 2], [3, 4]]
irb(main):023:0> Hash[*a.flatten]
  => {1=>2, 3=>4}
 5
Author: Jenorish,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-03-06 09:52:18