2009-03-05 8 views
2

Je suis novice en ruby ​​et je sens que je fais encore beaucoup de choses de manière C sharpish :-). Supposons que vous ayez un tableau d'objets (Question: has_many =>: réponses). Je veux parcourir toutes les réponses et si certaines réponses répondent à un critère, changer l'attribut de réponse. Actuellement, je fais comme suit:Meilleure façon de parcourir une séquence et de changer un objet à la fois (Ruby)

def iterate_and_do_stuff 
    for (a in self.answers) 
     if(a.somecriteria==true) 
     a.some_attr=some_val 
     end 
    end 
end 

Quelles sont les autres façons de le faire? Blocs, boucles, etc.

Veuillez nous contacter.

Merci.

Répondre

12

Utilisation Array#each:

self.answers.each {|a| a.some_attr = some_val if a.some_criteria}

+0

wow, 6 lignes coupées, merci – Valentin

+0

Ça va aussi être plus efficace que d'utiliser #select suivi de #each parce que vous n'aurez qu'à parcourir le tableau une fois . – Pesto

1

Juste pour le plaisir une alternative

self.answers.select{|a| a.some_criteria}.each{|a| a.some_attr = some_val} 
+0

qu'en est-il de convertir ceci en do..end blocks? – Valentin

+0

Battez-moi par 2 minutes. Putain d'avoir à chercher la documentation. –

+0

SO semble toujours comme une course :-) – Valentin

2
self.answers.select{|a| a.somecriteria}.each{|a| a.some_attr = some_val} 

OU

self.answers.find_all{|a| a.somecriteria}.each{|a| a.some_attr = some_val} 

Les deux sont moins efficaces que y notre code original, cependant.

4

Je préfère la carte! ou collectionnez! dans ce cas, parce que vous pouvez utiliser le! méthode pour représenter sémantiquement vous modifiez le tableau en place.

self.answers.map!{ |a| 
    a.some_criteria ? (a.some_attr = some_val) : a.some_attr 
} 

ou

self.answers.collect!{ |a| 
    a.some_criteria ? (a.some_attr = some_val) : a.some_attr 
} 

De cette façon, il est très clair que vous avez l'intention de changer le tableau.

1

Si vous travaillez avec des modèles ActiveRecord, n'oubliez pas que vous pouvez effectuer votre sélection au niveau de la base de données plutôt qu'en mémoire. Pour reformuler, vous pouvez extraire de la base de données uniquement les valeurs que vous souhaitez dans votre tableau, puis simplement les modifier.

Voici un exemple en utilisant trouveurs personnalisés (sorte d'une façon plus de le faire):

class Question < ActiveRecord::Base 
    has_many :answers do 
    def accepted 
     find :all, :conditions => { :accepted => true } 
    end 
    end 
end 

class Answer < ActiveRecord::Base 
    belongs_to :question 
end 

q = Question.find :first 
q.answers.accepted.each { |a| a.do_something! } 

ou vous pouvez le faire avec une autre association:

class Question < ActiveRecord::Base 
    has_many :answers 
    has_many :accepted_answers, :class_name => "Answer", :conditions => { :accepted => true } 
end 

class Answer < ActiveRecord::Base 
    belongs_to :question 
end 

q = Question.find :first 
q.accepted_answers.each { |a| a.do_something! } 

Voici un autre exemple en utilisant named scopes (un peu plus récent, et préféré à mon avis) sur votre classe enfant:

class Question < ActiveRecord::Base 
    has_many :answers 
end 

class Answer < ActiveRecord::Base 
    belongs_to :question 
    named_scope :accepted, :conditions => { :accepted => true } 
end 

q = Question.find :first 
q.answers.accepted.each { |a| a.do_something! } 

Mais dans tout des cas, vous avez Abstraite la « sélection », qui a quelques avantages:

  1. plus rapide dans les cas de grandes collections
  2. Vous avez Abstraite les plus bas critères de sélection de niveau à quelque chose avec le sens sémantique de niveau supérieur , ce qui rend votre code plus facile à lire et à maintenir
Questions connexes