2010-07-26 3 views
23

Je suis une personne Perl et je l'ai fait Hashes comme ça pendant un certain temps:Création d'une ligne de hachage imbriquée dans Ruby? (Je viens de Perl)

 
my %date; 

#Assume the scalars are called with 'my' earlier 

$date{$month}{$day}{$hours}{$min}{$sec}++ 

Maintenant, je suis d'apprentissage Ruby et je l'ai trouvé jusqu'à présent que l'utilisation de cet arbre est le moyen de faire beaucoup de clés et une valeur. Est-il possible d'utiliser le format simple que j'utilise avec Perl en utilisant une ligne?

 
@date = {                                          
     month => {                                         
      day => {                                         
      hours => {                                        
       min => {                                        
       sec => 1                                       
       }                                          
      }                                          
      }                                           
     }                                                                                      
     }     
+0

Je ne sais pas une façon de faire de la boîte. Vous pourriez probablement étendre la classe Array ou Hash avec une méthode qui prend quelque chose comme '[month, day, hours, min, sec, 1]' comme argument et le convertit en ce type de hash pour vous, si c'est quelque chose que vous pense est utile. – Karl

+0

Il me semble que les gens de Ruby utilisent une manière différente de stocker des informations dans un script en cours d'exécution. J'utilise des hashes comme des fous dans perl pour garder mes données uniques et catégorisées. Existe-t-il une meilleure méthode pour stocker des données dans ce cas? J'utilise cet extrait dans un script d'analyse de journal et d'autres clés peuvent être ajoutées pour différentes entrées de journal que je dois surveiller et classer. – BioDevMike

+1

Autres questions de "hash autovivification dans Ruby": http://stackoverflow.com/questions/170223/hashes-of-hashes-idiom-in-ruby http://stackoverflow.com/questions/3148747/is-auto-initialization -d-multidimensionnel-hash-array-possible-dans-ruby-as-it-is et http://stackoverflow.com/questions/3172342/how-to-handle-combination-for-auto-vivifying-hash -in-ruby –

Répondre

41

Malheureusement, il y a pas de manière simple et pratique. Un équivalent Ruby serait une vilaine bête, laide comme:

((((@date[month] ||= {})[day] ||= {})[hours] ||= {})[min] ||= {})[sec] = 1 

Il y a une façon d'attribuer valeurs par défaut pour les clés manquantes hash, bien que:

@date = Hash.new { |hash, key| hash[key] = {} } 

# @date[:month] is set to a new, empty hash because the key is missing. 
@date[:month][:day] = 1 

Malheureusement, cela ne fonctionne pas récursive .

... sauf si vous créez-le vous-même; Hourra pour Ruby!

class Hash 
    def self.recursive 
    new { |hash, key| hash[key] = recursive } 
    end 
end 

@date = Hash.recursive 
@date[month][day][hours][min][sec] = 1 
# @date now equals {month=>{day=>{hours=>{min=>{sec=>1}}}}} 

Gardez à l'esprit, cependant, que toutes les valeurs non définies sont maintenant {} plutôt que nil.

+0

Merci pour votre réponse. Encore une chose. Comment allez-vous stocker les données analysées? J'utilise des hachages dans Perl. Que pensez-vous de stocker des données parsées catégorisées? (Mon autre commentaire à mon poste de question a plus) – BioDevMike

+0

Si vous avez besoin des données disponibles par mois, par mois + jour, par mois + jour + heure, etc., alors votre approche est ok. Si vous avez besoin de faire autre chose avec, alors cela dépend vraiment de votre cas d'utilisation. Vous pourriez même être bien juste en utilisant un tableau comme '[mois, jour, heures, min, sec]' ou une chaîne simple comme clé de hachage; mais je ne peux pas dire sans en savoir plus. – molf

+0

J'ai également trouvé que je pouvais coller facilement des symboles en faisant: @date [month.to_sym] [day.to_sym] [heures.to_sym] [min.to_sym] [sec.to_sym] = + 1 De toute façon de coller ça dans cette fonction récursive aux touches auto sym? – BioDevMike

1

symboles à l'aide semblait fonctionner:

ree-1.8.7-2009.10 > @date = {:month =>{:day => {:hours => {:min => {:sec => 1 } } } } } 
=> {:month=>{:day=>{:hours=>{:min=>{:sec=>1}}}}} 

Je peux alors récupérer le val comme ceci:

ree-1.8.7-2009.10 > @date[:month][:day] 
=> {:hours=>{:min=>{:sec=>1}}} 
+3

Pas une réponse utile. – friedo

+0

Vraiment? Voir ci-dessus .... – nicholasklick

+0

Maintenant que vous l'avez édité, je vais supprimer mon -1 :) – friedo

1

Il ne ressemble pas à Ruby peut faire autovivification dès le début, mais vous pouvez facilement ajouter cette fonctionnalité. Une recherche pour « autovivification rubis » sur Google donne:

http://t-a-w.blogspot.com/2006/07/autovivification-in-ruby.html

qui contient un exemple de bonne façon de créer un hachage qui fonctionnera la façon dont vous recherchez.

ruby hash autovivification (facets) pourrait également vous être utile.

+0

Merci pour ces liens. Vous obtenez la deuxième place. J'ai appris un nouveau mot "autovivification". – BioDevMike

1

Vous pouvez utiliser la Facets gem Hash.autonew pour faire la même chose que la fonction recursive donnée dans la réponse de Molf.

13

Voici quelques options similaires à la réponse donnée par @molf mais sans le patch de singe.

En utilisant une méthode de fabrication:

def hash_tree 
    Hash.new do |hash, key| 
     hash[key] = hash_tree 
    end 
    end 

    @date = hash_tree 
    @date[month][day][hours][min][sec] = 1 

Avec une classe personnalisée:

class HashTree < Hash 
    def initialize 
     super do |hash, key| 
     hash[key] = HashTree.new 
     end 
    end 
    end 

    @date = HashTree.new 
    @date[month][day][hours][min][sec] = 1 
16
->f{f[f]}[->f{Hash.new{|h,k|h[k]=f[f]}}] 

De toute évidence.

+9

Idéal pour ceux qui viennent de perl – artemave

+0

Il m'a fallu 20 minutes pour le comprendre. Je ne serai pas capable de le reproduire. Mais c'est cool. – artemave

+1

Veuillez ajouter des explications. – artemave

11

Par rapport à l'expression lambda donnée ci-dessus, cela est plus simple et aussi en une ligne:

Hash.new {|h,k| h[k] = Hash.new(&h.default_proc) } 
Questions connexes