Ruby: различное количество регистра состояний - PullRequest
2 голосов
/ 03 апреля 2020

В настоящее время я пишу автоматизированную программу формирования команды на Ruby, которая создает гетерогенные команды на основе навыков студентов. Навык определяется на основе оценки учащегося за предыдущий год (т. Е. Целое число в диапазоне [0; 100]). Я реализовал стандартную версию метода преобразования классов в навыки, где оценка преобразуется в навыки в соответствии со следующими пороговыми значениями

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

И это реализуется с помощью оператора case / when. Однако программа будет разработан для использования учителем, и я хочу предоставить учителю возможность дать свою собственную интерпретацию того, как измерять навыки ученика (например, он может хотеть иметь меньшее или большее количество групп навыков или другой порог для данного группы навыков). Моя идея состоит в том, что он сможет передать их в качестве именованного аргумента в форме ha sh, с 2-значным массивом в качестве ключа (пороги оценки) и целым числом в качестве значения (навыка), однако я изо всех сил пытается придумать аккуратный способ его реализации. Есть ли возможность реализовать переменное число операторов when, где каждый отвечает за данный навык (например, помещая их в некоторый вид l oop?). Или вы можете придумать какой-нибудь другой способ решить эту проблему? Заранее большое спасибо за помощь!

Ответы [ 2 ]

3 голосов
/ 03 апреля 2020

С учетом структуры, подобной этой:

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

Вы можете использовать find, чтобы получить первую запись, соответствующую определенному условию: (при условии, что диапазоны не перекрываются и что «дыр» нет - вы можете сначала проверить предоставленные данные)

grade = 52

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

range #=> 50..59
skill #=> 3
2 голосов
/ 03 апреля 2020

Использование bsearch более производительно, чем find, если вы можете гарантировать упорядоченный массив - O(log n) против find O(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
...