De acuerdo, así que aquí está el trato, he estado buscando en Google durante años para encontrar una solución a esto y, aunque 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 'pares' son las claves y los elementos en los índices 'impares' son los valores.
¿Alguna idea de cómo hacer esto limpiamente? Supongo que un método de fuerza bruta sería extraer todos los índices pares en una matriz separada y luego recorrerlos para agregar los valores.
*
se llama el operador splat . Toma una matriz y la convierte en una lista literal de elementos. Entonces*[1,2,3,4]
=>1, 2, 3, 4
. En este ejemplo, lo anterior es equivalente a hacerHash["item 1", "item 2", "item 3", "item 4"]
. YHash
tiene un[]
método que acepta una lista de argumentos (haciendo claves de índices pares y valores de índices impares), peroHash[]
no acepta una matriz, por lo que la utilizamos*
.Hash[a.each_slice(2).to_a]
.Ruby 2.1.0 introdujo un
to_h
método en Array que hace lo que usted requiere 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 .fuente
bar
debe ser un símbolo, y el símbolo:2
debe ser un número entero. Entonces, tu expresión corregida esa = [[:foo, 1], [:bar, 2]]
).Solo use
Hash.[]
con los valores en la matriz. Por ejemplo:fuente
*arr
conviertearr
en una lista de argumentos, por lo que se llama al[]
método de Hash con el contenido de arr como argumentos.O si tiene una matriz de
[key, value]
matrices, puede hacer:fuente
Hash[*arr]
{ [1, 2] => [3, 4] }
. Y dado que el título de la pregunta dice "Array to Hash" y el método incorporado "Hash to Array" lo hace:{ 1 => 2, 3 => 4}.to_a # => [[1, 2], [3, 4]]
pensé que más de uno podría terminar aquí tratando de obtener la inversa del método incorporado "Hash to Array". En realidad, así es como terminé aquí de todos modos.Hash[arr]
hará el trabajo por ti.#inject
método. Con#merge!
,#each_with_object
debería haber sido utilizado. Si#inject
se insiste en él, en#merge
lugar de#merge!
haberlo usado.Esto es lo que estaba buscando cuando busqué en Google:
[{a: 1}, {b: 2}].reduce({}) { |h, v| h.merge v } => {:a=>1, :b=>2}
fuente
merge
, construye y descarta una nueva iteración de hash por ciclo y es muy lenta. Si tiene una variedad de hash, intente en su[{a:1},{b:2}].reduce({}, :merge!)
lugar: combina todo en el mismo hash (nuevo)..reduce(&:merge!)
[{a: 1}, {b: 2}].reduce(&:merge!)
evalúa a{:a=>1, :b=>2}
[{a: 1}, {b: 2}].reduce(&:merge!)
es lo mismo[{a: 1}, {b: 2}].reduce { |m, x| m.merge(x) }
que lo mismo[{b: 2}].reduce({a: 1}) { |m, x| m.merge(x) }
.Enumerator
incluyeEnumerable
. Desde entonces2.1
,Enumerable
también tiene un método#to_h
. Por eso, podemos escribir:Porque
#each_slice
sin bloque nos daEnumerator
, y según la explicación anterior, podemos llamar al#to_h
método en elEnumerator
objeto.fuente
Podrías intentarlo así, para una sola matriz
para la matriz de la matriz
fuente
o, si odias
Hash[ ... ]
:o, si eres un fanático perezoso de la programación funcional rota:
fuente
Hash[ ... ]
pero quieres usarlo como un método encadenado (como puedes hacerloto_h
), puedes combinar las sugerencias de Boris y escribir:arr.each_slice( 2 ).map { |e| e }.tap { |a| break Hash[a] }
Todas las respuestas suponen que la matriz inicial es única. OP no especificó cómo manejar matrices con entradas duplicadas, lo que resulta en claves duplicadas.
Miremos a:
Perderá el
item 1 => item 2
par ya que se anula bijitem 1 => item 5
:Todos los métodos, incluido el
reduce(&:merge!)
resultado en la misma eliminación.Sin embargo, podría ser que esto es exactamente lo que esperas. Pero en otros casos, es probable que desee obtener un resultado con un
Array
valor for:La forma ingenua sería crear una variable auxiliar, un hash que tenga un valor predeterminado y luego completarlo en un bucle:
Puede ser posible usar
assoc
yreduce
hacer lo anterior en una línea, pero eso se vuelve mucho más difícil de razonar y leer.fuente