2009-10-23 9 views
0

Je le tableau suivant:Trier et valeurs magasin de tableau multidimensionnel dans le nouveau tableau dans Ruby

votes_array = [["2", "1"], ["2", "4"], ["4", "3"], ["3", "4"], ["1", "N"], ["3", "1"], ["1", "2"], ["4", "1"], ["0", "1"], ["0", "2"], ["1", "3"], ["1", "4"]] 

Et je veux créer un nouveau tableau (ou hachage) qui stocke les éléments de votes_array par leur première option si que le nouveau tableau ressemble à ceci:

candidate_votes = [ 
        {"id" => "0", "votes" => [["0", "1"],["0","2"]]}, 
        {"id" => "1", "votes" => [["1", "N"],["1","2"],["1","3"],["1","4"]]}, 
        etc, 
        etc] 

l'ordre des votes dans la clé « votes » est pas important, juste que tous les votes se séparent dans les ids pertinents.

Je l'ai travailler avec le code suivant:

first_preferences = votes_array.map(&:first) 
valid_candidates = first_preferences.uniq 
valid_candidates.each do |candidate| 
    these_votes = votes_array.find_all { |i| i[0] == candidate } 
    candidate_votes << {"id" => candidate, "votes" => these_votes} 
end 

Mais se demande s'il y a un plus élégant, plus propre ou Rubiyst façon?

Répondre

4

Avec Ruby 1.8.7+, il est en une ligne:

candidate_votes = votes_array.group_by {|pair| pair[0]} 

impression Jolie candidate_votes retourne

{"0"=>[["0", "1"], ["0", "2"]], 
"1"=>[["1", "N"], ["1", "2"], ["1", "3"], ["1", "4"]], 
"2"=>[["2", "1"], ["2", "4"]], 
"3"=>[["3", "4"], ["3", "1"]], 
"4"=>[["4", "3"], ["4", "1"]]} 
+0

Fonctionnalité impressionnante. +1 –

1

En voici un qui crée candidate_votes en tant que hachage. Il est probablement un peu plus vite parce que vous devez itérer votes_array une seule fois:

candidate_votes = {} 
votes_array.each do |id, vote| 
    candidate_votes[id] ||= {"id" => id, "votes" => []} 
    candidate_votes[id]["votes"] << [id, vote] 
end 

Cela donnera des résultats comme celui-ci:

candidate_votes = { 
        "0" => {"votes" => [["0", "1"], ["0", "2"]], "id" => "0"}, 
        ... etc ... 
        } 
+0

Merci Pesto, peut-être que je dois ajouter que l'identifiant ne peut pas être séquentielle - que devrait toujours fonctionner avec votre suggestion, n'est-ce pas? Et y a-t-il quelque chose qui ne va pas dans la façon dont je l'ai fait? – Les

+0

Ma solution ne repose pas sur l'id étant séquentielle ou les votes étant dans un ordre particulier. Votre réponse est logique, mais inefficace. Vous passez par 'votes_array' pour créer un autre tableau composé uniquement des premiers caractères. Ensuite, vous passez à travers ce tableau pour générer les entrées uniques. Ensuite, vous passez par * ce * tableau, et pour chaque article, vous passez à nouveau par 'votes_array'. Ce n'est peut-être pas un problème réel dans votre situation, mais cela mérite d'être mentionné. Le mien passe par 'votes_array' qu'une seule fois. – Pesto

-1

Je pense que vous pouvez organiser la sortie beaucoup plus concise en utilisant quelque chose comme ça :

# Use Enumerable#inject to convert Array to Hash 
results = votes_array.inject({ }) do |hash, vote| 
    # Create hash entry for candidate if not defined (||=) 
    hash[vote[0]] ||= { :votes => [ ] } 

    # Add vote to candidate's array of votes 
    hash[vote[0]][:votes] << vote[1] 

    # Keep hash for next round of inject 
    hash 
end 

# => {"0"=>{:votes=>["1", "2"]}, "1"=>{:votes=>["N", "2", "3", "4"]}, "2"=>{:votes=>["1", "4"]}, "3"=>{:votes=>["4", "1"]}, "4"=>{:votes=>["3", "1"]}} 

Comme une note, il est avantageux d'utiliser des symboles pour les clés de hachage en Ruby, car ils sont généralement plus efficaces que les chaînes de ce genre de pplication.

+0

Je pensais faire de même, mais cela ne produit pas de sortie dans le format demandé. – Pesto

+0

J'essayais juste de faire une sorte de solution "plus élégante, plus propre ou plus Rubiyst"! :) – tadman

Questions connexes