Ruby:不同数量的 case 语句

Ruby: Varying Number of case statemnts

我目前正在 Ruby 编写一个自动化的团队组建程序,它根据学生的技能组成不同的团队。该技能来自前一年学生的成绩(即 [0;100] 范围内的整数)。我已经实现了一个默认版本的成绩到技能转换方法,其中成绩根据以下阈值转换为技能

[0;39] => 1
[40;49] = > 2 
[50;59] = > 3
[60;69] = > 4
[70;79] = > 5
[80;100] = > 6

这是通过 case/when 语句实现的 但是,该程序将根据教师的使用而设计,我想让教师能够对如何衡量学生的技能做出自己的解释(例如,他可能希望拥有更少或更多的技能组或给定技能组的不同阈值)。 我的想法是他将能够以哈希的形式将它们作为命名参数传递,将 2 值数组作为键(成绩阈值)和整数作为值(技能),但是我正在努力思考一个巧妙的方法来实现它。 是否有可能实现可变数量的 when 语句,其中每个语句负责给定的技能(比如将它们放在某种循环中?)。或者你能想到任何其他方法可以解决这个问题吗? 非常感谢您的帮助!

给定这样的结构:

values = {
  0..39 => 1,
  40..49 => 2,
  50..59 => 3,
  60..69 => 4,
  70..79 => 5,
  80..100 => 6
}

您可以使用 find 来获取符合特定条件的第一个条目:(假设范围不重叠并且没有 "holes" – 您可能想要验证提供的数据第一)

grade = 52

range, skill = values.find { |r, v| r.cover?(grade) }

range #=> 50..59
skill #=> 3

使用 bsearchfind 性能更高,只要你能保证数组有序 – O(log n) vs findO(n) –没有任何额外的内存支出(堆栈框架除外,呵呵)。此外,由于您的范围(大概)是连续的,它们之间没有任何空洞,您可以只指定阈值。

因此,如果您的索引始终为“1..N”,则此方法可行:

def grade(points, scale)
  scale.bsearch_index { |x| points < x }
end

scale = [0, 40, 50, 60, 70, 80, 101]
grade(39, scale)
# => 1
grade(40, scale)
# => 2

如果没有,那么使用这个:

def grade(points, scale)
  scale.to_a.bsearch { |upto, _| points < upto }.last
end

scale = {40 => 1, 50 => 2, 60 => 3, 70 => 4, 80 => 5, 101 => 6}
grade(39, scale)
# => 1
grade(40, scale)
# => 2