是否有更惯用的 ruby 来执行此迭代?
Is there more idiomatic ruby to perform this iteration?
我正在遍历一组 id,并希望 return 第一个对象 return 在其上调用谓词方法时 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 子类型)来找到所需的东西。
您有:
desired_thing = ids.detect do |id|
thing = Thing.new(id)
return thing if thing.true?
end
如果找到 thing
,其中 thing.true?
是 true
,detect
永远不会 returns ids
的元素(要分配到 desired_thing
) 因为它被 return
抢占了。另一方面,如果块在没有调用 return
的情况下完成,detect
returns nil
并将该值分配给 desired_thing
,但是 nil
值在后面的代码中没有用。因此最好只写:
ids.each do |id|
thing = Thing.new(id)
return thing if thing.true?
end
我想你快到了。
根据 find_by_id
方法,我假设 Question
是具有某种 ActiveRecord
功能的 class,所以我希望 where
方法也存在。
在那种情况下:
applicable_question = Question.where(id: ids).order(...).detect do |question|
question.applicable_for?(self)
end
会做的很好。
感觉不像是在滥用detect
,你只需要拥有正确的可枚举对象集即可。
更新
如果实例化太多对象不是一个可接受的解决方案,那么 是可行的方法。请记住,这两种方法都有其缺点。
Question.where(id: ids).order(...).detect {|q| q.condition? }
将对数据库执行单个查询但实例化太多对象。
ids.each {|id| q = Question.find(id); return q if q.condition? }
将对数据库执行太多查询但一次只实例化一个对象
第一种方法总是很繁重(内存方面),而第二种方法的性能取决于您检索记录的顺序,并且也可能变得非常昂贵。
最佳选择也取决于您的数据集。如果你有成千上万的问题,第一种方法是不可能的。
也许最好的选择是尝试以 condition?
更可能为真的方式对记录进行排序
你所拥有的与你想要做的相差不远。我会做类似的事情:
desired_thing = ids.detect{ |id| Thing.new(id) }
我不确定您是否想远离 SQL 方法,例如 find_by_id 或其他方法,但我相信您也可以使用这些方法,除非您需要使用检测(或查找)。
我正在遍历一组 id,并希望 return 第一个对象 return 在其上调用谓词方法时 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 子类型)来找到所需的东西。
您有:
desired_thing = ids.detect do |id|
thing = Thing.new(id)
return thing if thing.true?
end
如果找到 thing
,其中 thing.true?
是 true
,detect
永远不会 returns ids
的元素(要分配到 desired_thing
) 因为它被 return
抢占了。另一方面,如果块在没有调用 return
的情况下完成,detect
returns nil
并将该值分配给 desired_thing
,但是 nil
值在后面的代码中没有用。因此最好只写:
ids.each do |id|
thing = Thing.new(id)
return thing if thing.true?
end
我想你快到了。
根据 find_by_id
方法,我假设 Question
是具有某种 ActiveRecord
功能的 class,所以我希望 where
方法也存在。
在那种情况下:
applicable_question = Question.where(id: ids).order(...).detect do |question|
question.applicable_for?(self)
end
会做的很好。
感觉不像是在滥用detect
,你只需要拥有正确的可枚举对象集即可。
更新
如果实例化太多对象不是一个可接受的解决方案,那么
Question.where(id: ids).order(...).detect {|q| q.condition? }
将对数据库执行单个查询但实例化太多对象。ids.each {|id| q = Question.find(id); return q if q.condition? }
将对数据库执行太多查询但一次只实例化一个对象
第一种方法总是很繁重(内存方面),而第二种方法的性能取决于您检索记录的顺序,并且也可能变得非常昂贵。
最佳选择也取决于您的数据集。如果你有成千上万的问题,第一种方法是不可能的。
也许最好的选择是尝试以 condition?
更可能为真的方式对记录进行排序
你所拥有的与你想要做的相差不远。我会做类似的事情:
desired_thing = ids.detect{ |id| Thing.new(id) }
我不确定您是否想远离 SQL 方法,例如 find_by_id 或其他方法,但我相信您也可以使用这些方法,除非您需要使用检测(或查找)。