代码之家  ›  专栏  ›  技术社区  ›  Valentin V

迭代序列并一次更改一个对象的最佳方法(Ruby)

  •  2
  • Valentin V  · 技术社区  · 15 年前

    我对Ruby还不熟悉,我觉得我仍然会以C语言的方式做很多事情。 假设您有一个对象数组(问题:有多个=>:答案)。 我想迭代所有答案,如果一些答案满足条件,则更改答案属性。 目前我做的如下:

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

    其他的方法是什么?块、环等?

    拜托。

    谢谢您。

    5 回复  |  直到 15 年前
        1
  •  12
  •   Pesto    15 年前

    使用 Array#each :

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

        2
  •  4
  •   berlin.ab    15 年前

    我喜欢地图!或者收集!在这种情况下,因为您可以使用!方法在语义上表示您正在就地更改数组。

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

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

    这样,很明显您打算更改数组。

        3
  •  2
  •   Chris Doggett    15 年前
    self.answers.select{|a| a.somecriteria}.each{|a| a.some_attr = some_val}
    

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

    不过,这两种方法的效率都低于原始代码。

        4
  •  1
  •   DanSingerman    15 年前

    只是为了好玩另一个选择

    self.answers.select{|a| a.some_criteria}.each{|a| a.some_attr = some_val}
    
        5
  •  1
  •   Ian Terrell    15 年前

    如果您使用的是ActiveRecord模型,请不要忘记您可以在数据库级别而不是在内存中进行选择。要重新措辞,您只能从数据库中检索您想要的值到数组中,然后简单地更改这些值。

    下面是一个使用自定义查找器的示例(有点像以前的方法):

    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! }
    

    或者你可以和另一个协会合作:

    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! }
    

    下面是另一个在您的孩子类中使用命名作用域的示例(更新一点,在我看来是首选的):

    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! }
    

    但是在任何一种情况下,您都抽象出了“选择”,这有一些好处:

    1. 在大型收藏中更快
    2. 您已经将较低级别的选择标准抽象为具有较高级别语义意义的内容,这使得您的代码更易于阅读和维护。