Bon, voici le contrat. Cela fait très longtemps que je recherche des solutions sur ce site dans Google. Bien qu’il en existe beaucoup, ils ne semblent pas faire le travail que je recherche.
Fondamentalement, j'ai un tableau structuré comme celui-ci
["item 1", "item 2", "item 3", "item 4"]
Je veux convertir ceci en un hachage afin qu'il ressemble à ceci
{ "item 1" => "item 2", "item 3" => "item 4" }
c'est-à-dire que les éléments figurant dans les index "pairs" sont les clés et les éléments figurant dans les index "impairs" sont les valeurs.
Des idées comment faire cela proprement? Je suppose qu'une méthode de force brute consisterait simplement à extraire tous les index pairs dans un tableau séparé, puis à les contourner pour ajouter les valeurs.
a = ["item 1", "item 2", "item 3", "item 4"]
h = Hash[*a] # => { "item 1" => "item 2", "item 3" => "item 4" }
C'est ça. Le *
est appelé l'opérateur splat.
Un avertissement par @ Mike Lewis (dans les commentaires): "Soyez très prudent avec ceci. Ruby élargit les splats sur la pile. Si vous faites cela avec un grand jeu de données, attendez-vous à ce que votre pile s'épuise."
Ainsi, dans la plupart des cas d'utilisation générale, cette méthode est excellente, mais utilisez une méthode différente si vous souhaitez effectuer la conversion sur de nombreuses données. Par exemple, @ Łukasz Niemier (également dans les commentaires) propose cette méthode pour les grands ensembles de données:
h = Hash[a.each_slice(2).to_a]
Ruby 2.1.0 a introduit une méthode to_h
sur Array qui répond à vos besoins si votre tableau d'origine est constitué de tableaux de paires clé-valeur: 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}
Utilisez simplement Hash.[]
avec les valeurs du tableau. Par exemple:
arr = [1,2,3,4]
Hash[*arr] #=> gives {1 => 2, 3 => 4}
Ou si vous avez un tableau de tableaux [key, value]
, vous pouvez faire:
[[1, 2], [3, 4]].inject({}) do |r, s|
r.merge!({s[0] => s[1]})
end # => { 1 => 2, 3 => 4 }
Voici ce que je cherchais en recherchant ceci:
[{a: 1}, {b: 2}].reduce({}) { |h, v| h.merge v } => {:a=>1, :b=>2}
Enumerator
comprend Enumerable
. Depuis _2.1
_, Enumerable
a également une méthode #to_h
. C'est pourquoi, nous pouvons écrire: -
_a = ["item 1", "item 2", "item 3", "item 4"]
a.each_slice(2).to_h
# => {"item 1"=>"item 2", "item 3"=>"item 4"}
_
Parce que #each_slice
sans bloc nous donne Enumerator
, et comme expliqué ci-dessus, nous pouvons appeler la méthode _#to_h
_ sur le Enumerator
objet.
Vous pouvez essayer comme ça, pour un seul tableau
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"}
pour tableau de tableau
irb(main):022:0> a = [[1, 2], [3, 4]]
=> [[1, 2], [3, 4]]
irb(main):023:0> Hash[*a.flatten]
=> {1=>2, 3=>4}
a = ["item 1", "item 2", "item 3", "item 4"]
Hash[ a.each_slice( 2 ).map { |e| e } ]
ou si vous détestez Hash[ ... ]
:
a.each_slice( 2 ).each_with_object Hash.new do |(k, v), h| h[k] = v end
ou, si vous êtes un fan fainéant de programmation fonctionnelle interrompue:
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"
Toutes les réponses supposent que le tableau de départ est unique. OP n'a pas précisé comment gérer les tableaux contenant des entrées en double, ce qui entraîne la duplication des clés.
Regardons:
a = ["item 1", "item 2", "item 3", "item 4", "item 1", "item 5"]
Vous perdrez la paire item 1 => item 2
car elle est remplacée par item 1 => item 5
:
Hash[*a]
=> {"item 1"=>"item 5", "item 3"=>"item 4"}
Toutes les méthodes, y compris la reduce(&:merge!)
, entraînent la même suppression.
Il se pourrait que ce soit exactement ce que vous attendez, cependant. Mais dans d'autres cas, vous souhaiterez probablement obtenir un résultat avec un Array
comme valeur:
{"item 1"=>["item 2", "item 5"], "item 3"=>["item 4"]}
La manière naïve serait de créer une variable d'assistance, un hachage qui a une valeur par défaut, puis de la remplir en boucle:
result = Hash.new {|hash, k| hash[k] = [] } # Hash.new with block defines unique defaults.
a.each_slice(2) {|k,v| result[k] << v }
a
=> {"item 1"=>["item 2", "item 5"], "item 3"=>["item 4"]}
Il est peut-être possible d'utiliser assoc
et reduce
à faire en haut d'une ligne, mais cela devient beaucoup plus difficile à raisonner et à lire.