我正在迭代一组id并希望返回第一个在调用谓词方法时返回true
的对象。几行代码值得千言万语:
def applicable_question(question_ids)
ordered_ids(question_ids, order).detect do |question_id|
question = Question.find_by(id: question_id)
return question if question.applicable_for?(self)
end
end
剥离域名条款:
def desired_thing(ids)
ids.detect do |id|
thing = Thing.new(id)
return thing if thing.true?
end
end
这里有更惯用的方法吗?具体来说,我觉得我在滥用detect
。我立即联系了each
和break
,但这种做法并没有走得太远。
此代码的要求是不需要实例化大量对象(例如ActiveRecord子类型)来查找所需的内容。
答案 0 :(得分:2)
你有:
desired_thing = ids.detect do |id|
thing = Thing.new(id)
return thing if thing.true?
end
如果找到thing
thing.true?
为true
的{{1}},则detect
永远不会返回ids
的元素(将被分配到desired_thing
)因为它被return
抢占了。另一方面,如果块在未调用return
的情况下完成,detect
会返回nil
并将该值分配给desired_thing
,但nil
值为ids.each do |id|
thing = Thing.new(id)
return thing if thing.true?
end
在后面的代码中没有用。因此,最好只写:
{{1}}
答案 1 :(得分:1)
我想你差点就到了。
从find_by_id
方法,我假设Question
是一个具有某种ActiveRecord
功能的类,所以我希望也存在where
方法。
在那种情况下:
applicable_question = Question.where(id: ids).order(...).detect do |question|
question.applicable_for?(self)
end
会做得很好。
它不想滥用detect
,你只需拥有正确的可枚举对象集。
如果实例化太多对象不是一个可接受的解决方案,那么https://stackoverflow.com/a/29176622/687142就是可行的方法。请记住,这两种方法都有其缺点。
Question.where(id: ids).order(...).detect {|q| q.condition? }
将对数据库执行单个查询,但会实例化太多对象。ids.each {|id| q = Question.find(id); return q if q.condition? }
将对数据库执行太多查询,但一次只实例化一个对象第一种方法是持续繁重(记忆明智),而第二种方法的性能取决于您检索记录的顺序,并且也可能变得非常昂贵。
最佳选择也取决于您的数据集。如果您有数十万个问题,那么第一种方法是不可能的。
也许最好的选择是尝试以condition?
更可能真实的方式订购记录
答案 2 :(得分:0)
你所拥有的与你想要做的事情相去甚远。我会做类似的事情:
desired_thing = ids.detect{ |id| Thing.new(id) }
我不确定你是否试图远离像find_by_id这样的SQL方法,或者在哪里,但我相信你也可以使用它们,除非你需要使用detect(或find)。