ruby - 重构冗余循环逻辑
问题描述
我的代码应该从 QUIZ (MyQuiz) 中获取答案 (true),并将它们与 Root 类型进行比较。测验问题具有通过 RootProfile 与它们关联的类型(名称)。例如,
question.root_profile.name
会返回类似:
{question: "1", name: "ocean", ...}
我也应该知道我有什么类型的答案。
answer.question.root_profile.name
当我从 MyQuiz 取回所有真实答案时,我可以拥有 10 个海洋 6 只鸟 3 个轮胎。然后,基于此,我计算每个测验的百分位数。如果测验有 100 个问题,它将计算 10% 的海洋、6% 的鸟类和 3% 的轮胎。
代码如下:
module RootServices
class RootCount
def initialize (my_quiz)
@my_quiz = my_quiz
end
attr_reader :my_quiz
def root_counts(root_profile)
total = []
all_answers.each do |answer|
if answer.question.root_profile.name == root_profile.name
total << answer
end
end
total_percentage = (total.count.to_f / all_answers.count.to_f) * 100
element = {root_profile_id: root_profile.id, root_profile: root_profile.name, total: total_percentage}
return element
end
def root_branch
root_branch_total = []
# Pass root_profile object to root_counts and store in the root_branch_total array of hashes the returned element
root_profiles.each do |root_profile|
root_branch_total << root_counts(root_profile)
end
return root_branch_total
end
def root_profiles
title = RootProfile.all
end
def all_answers
all_answers = my_quiz.my_answers.where(answer: true)
end
end
end
它有效,但有点过于复杂,而且循环似乎是多余的。我想知道是否会有更优雅的方式。我的逻辑有效,但我的日志显示来自 Answers = true 的查询(假设我的测试有五个 true),其中五个查询针对 RootProfile,五个查询针对嵌套问题。这是一个视觉效果:
SELECT "my_answers".* FROM ...
SELECT "questions".* FROM "questions"
SELECT "root_profiles".* FROM "root_profiles"
SELECT "questions".* FROM "questions"
SELECT "root_profiles".* FROM "root_profiles"
SELECT "questions".* FROM "questions"
SELECT "root_profiles".* FROM "root_profiles"
SELECT "questions".* FROM "questions"
SELECT "root_profiles".* FROM "root_profiles"
SELECT "questions".* FROM "questions"
SELECT "root_profiles".* FROM "root_profiles"
SELECT "my_answers".* FROM ...
SELECT "questions".* FROM "questions"
SELECT "root_profiles".* FROM "root_profiles"
SELECT "questions".* FROM "questions"
SELECT "root_profiles".* FROM "root_profiles"
SELECT "questions".* FROM "questions"
SELECT "root_profiles".* FROM "root_profiles"
SELECT "questions".* FROM "questions"
SELECT "root_profiles".* FROM "root_profiles"
SELECT "questions".* FROM "questions"
SELECT "root_profiles".* FROM "root_profiles"
...
3x more
编辑:在下面添加重构代码
module RootServices
class RootCount
def initialize (my_quiz)
@my_quiz = my_quiz
@root_profiles = RootProfile.all
@all_answers = @my_quiz.my_answers.where(answer: true)
end
def root_branch
root_profiles.map { |root_profile| root_counts(root_profile) }
end
private
attr_reader :my_quiz, :root_profiles, :all_answers
def root_counts(root_profile)
answers = matching_answers(root_profile)
{
root_profile_id: root_profile.id,
root_profile: root_profile.name,
total: percentage_of_total(answers)
}
end
def matching_answers(root_profile)
all_answers.joins(question: :root_profile).where("root_profiles.name = ?", root_profile.name)
end
def percentage_of_total(answers)
(answers.count.to_f / all_answers.count.to_f) * 100
end
end
end
解决方案
首先,我认为您可能在 ruby 中遗漏了几个核心概念 - 最明显的是隐式返回 - 在您的代码的情况下,这意味着您不需要return
在方法末尾声明,而且您不需要不需要分配给单行中的局部变量。Ruby 就是这样。
您可以通过将要比较的所有名称收集到一个查询中来减少查询,而不是重复调用answer.question.root_profile.name
. 此外,您可能应该在 SQL 中进行选择,而不是立即将其转换为数组。我将为您重构一些方法,以提供一个示例,说明如何更好地做到这一点..类似于以下内容
def root_counts
answers = matching_answers(root_profile)
{
root_profile_id: root_profile.id,
root_profile: root_profile.name,
total: percentage_of_total(answers)
}
end
private
def root_profiles
RootProfile.all
end
def percentage_of_total(answers)
(answers.count.to_f / true_answers.count.to_f) * 100
end
def true_answers
my_quiz.my_answers.where(answer: true)
end
def matching_answers(root_profile)
true_answers
.joins(:questions, :root_profiles)
.where("root_profiles.name = ?", root_profile.name)
end
我不完全理解你试图用你的root_branch
方法做什么,因为我可以看到它返回一个数组,其中包含(1)数据库中所有对象的组合,和RootProfile
(2)一个集合包含该百分比计数的哈希root_profile
(由root_count
方法返回)。我认为你应该重新考虑这个逻辑。
另外,我可能会考虑将root_profiles
您使用类初始化的实例变量(也使用 an attr_reader
) - 因为它加载整个root_profiles
表,因此最好只调用一次
推荐阅读
- r - 基于日期的数据表拆分持续时间
- clojure - Clojure:异常后如何恢复REPL?
- stripe-payments - Stripe 中的重复电子邮件条目
- c++ - 在归并排序算法中,数组合并后释放左右子数组对空间复杂度有影响吗?
- agda - 用 Agda “重写” 证明“地图的合成就是合成的地图”
- c# - Laravel API 返回空白/空到 RestSharp C#
- c++11 - 可以在 C++ 中创建不同结构的数组
- ios - UISearchBar 文本未更新文件名列表
- c - 在 c 中使用指针进行字符串输入会给我一个函数中的分段错误。相同的代码块适用于另一个功能?
- scala - Spark Scala 中类型 DataSet[Row] 和 sql.DataFrame 之间的区别