Tableau de Hachage Ruby
Bon alors voici l'affaire, j'ai cherché sur google pour les âges à trouver une solution à ce et tandis qu'il ya beaucoup là-bas, ils ne semblent pas faire le travail, je suis à la recherche d'.
Fondamentalement, j'ai un tableau structuré comme ceci
["item 1", "item 2", "item 3", "item 4"]
Je veux convertir cette Hachage de sorte qu'il ressemble à ceci
{ "item 1" => "item 2", "item 3" => "item 4" }
c'est à dire les articles qui sont sur le 'même' index sont les clés et les éléments sur la "étrange" indices sont les valeurs.
Aucune idées de comment faire cela proprement? Je suppose que la force brutale méthode serait de simplement sortir tous le même index dans un tableau séparé et ensuite une boucle autour d'eux pour ajouter les valeurs.
Vous devez vous connecter pour publier un commentaire.
Que c'est. Le
*
est appelé le splat opérateur.Une mise en garde par @Mike Lewis (dans les commentaires): "il faut Être très prudent avec cela. Ruby se développe splats sur la pile. Si vous faites cela avec un grand jeu de données, attendez-vous à sauter hors de votre pile de jetons."
Si, pour la plupart générale des cas d'utilisation de cette méthode est grand, mais l'utilisation d'une autre méthode si vous voulez faire la conversion en lots de données. Par exemple, @Łukasz Niemier (également dans les commentaires) propose cette méthode de grands ensembles de données:
*
faire dans cet exemple?*
est appelé le splat de l'opérateur. Il prend un tableau et la convertit en un littéral liste d'éléments. Donc*[1,2,3,4]
=>1, 2, 3, 4
. Dans cet exemple, le ci-dessus est équivalent àHash["item 1", "item 2", "item 3", "item 4"]
. EtHash
a un[]
méthode qui accepte une liste d'arguments (ce qui fait que même des indices clés et les indices de valeurs), maisHash[]
ne pas accepter un tableau, de sorte que nous splat le tableau à l'aide de*
.def whatever *args
. Vous pouvez passer d'une liste commewhatever(7, 1, 3, 4)
. Et comme ci-dessus,*args
représente une liste etargs
représente un tableau. Puisque vous êtes de passage dans une liste, vous êtes réellement en passant dans le*args
. Ainsiargs
est un tableau, et que vous vous retrouvez avecargs == [7, 1, 3, 4]
. De sorte que vous pouvez passer en ce que les paramètres que vous voulez dans la méthode puis il suffit d'utiliserargs
pour y accéder.ArgumentError: odd number of arguments for Hash
Hash[a.each_slice(2).to_a]
.a.each_slice(2).to_h
(au moins dans YARV).to_h
fonctionne sur un tableau de tableaux. L'exécution de["item 1", "item 2", "item 3", "item 4"].to_h
résultats dansTypeError Exception: wrong element type String at 0 (expected array)
.[["item 1", "item 2"], ["item 3", "item 4"]].to_h
fonctionne bien. Je pense que @hauleth est droit, la bonne réponse lors de mes tests avec Ruby 2.5.3 esta.each_slice(2).to_h
each_slice(2).to_h
méthode, je l'avais déjà répertoriées dans ma réponse.Ruby 2.1.0 introduit un
to_h
méthode sur le Tableau qui fait ce que vous avez besoin si votre tableau original se compose de tableaux de paires clé-valeur: http://www.ruby-doc.org/core-2.1.0/Array.html#method-i-to_h.bar
doit être un symbole, le symbole:2
doit être un entier. Donc, votre expression corrigée esta = [[:foo, 1], [:bar, 2]]
).Suffit d'utiliser
Hash.[]
avec les valeurs dans le tableau. Par exemple:arr
dans une liste d'arguments, c'est l'appel de la[]
méthode de Hachage avec le contenu de l'arr comme arguments.Ou si vous disposez d'un tableau de
[key, value]
tableaux, vous pouvez le faire:Hash[*arr]
{ [1, 2] => [3, 4] }
. Et puisque la question du titre dit "Tableau de Hachage" et intégré dans le "Hachage de Tableau" la méthode n':{ 1 => 2, 3 => 4}.to_a # => [[1, 2], [3, 4]]
, j'ai pensé plus d'une pourrait se terminer ici, en essayant d'obtenir l'inverse de l'intégré dans le "Hachage de Tableau" la méthode. En fait, je suis arrivé ici de toute façon.Hash[arr]
fera le travail pour vous.#inject
méthode. Avec#merge!
,#each_with_object
doit avoir été utilisé. Si#inject
est exigé,#merge
plutôt que#merge!
doit avoir été utilisé.C'est ce que je cherchais lorsque vous tapez ceci:
[{a: 1}, {b: 2}].reduce({}) { |h, v| h.merge v }
=> {:a=>1, :b=>2}
merge
, elle construit et se défausse d'une nouvelle table de hachage par itération de boucle et est très lent. Si vous avez un tableau de hachages essayer[{a:1},{b:2}].reduce({}, :merge!)
plutôt - il fusionne le tout dans la même (nouveau) de hachage..reduce(&:merge!)
[{a: 1}, {b: 2}].reduce(&:merge!)
évalue à{:a=>1, :b=>2}
[{a: 1}, {b: 2}].reduce(&:merge!)
est le même que[{a: 1}, {b: 2}].reduce { |m, x| m.merge(x) }
qui est le même que[{b: 2}].reduce({a: 1}) { |m, x| m.merge(x) }
.{}
, ou de l'utilisation non-mutationmerge
qui a le même problème de performance tel que décrit ci-dessus; (2) le tableau d'entrée doit avoir au moins 1 élément, sinon vous obtiendreznil
en arrière au lieu d'un hachage videÉnumérateur
comprendÉnumérable
. Depuis2.1
,Enumerable
possède également une méthode#to_h
. C'est pourquoi, nous pouvons écrire :-Parce que
#each_slice
sans bloc nous donneEnumerator
, et que par l'explication ci-dessus, nous pouvons appeler la#to_h
méthode sur laEnumerator
objet.Vous pouvez essayer comme ça, pour le seul tableau
pour tableau de tableau
ou, si vous détestez
Hash[ ... ]
:ou, si vous êtes un paresseux fan de fractures de la programmation fonctionnelle:
Hash[ ... ]
mais vous voulez l'utiliser comme un enchaînés méthode (comme vous pouvez le faire avecto_h
) vous pouvez combiner Boris suggestions et à écrire:arr.each_slice( 2 ).map { |e| e }.tap { |a| break Hash[a] }