Я предполагаю, что отображение расстояний до лазеров - это данные, а не хеш, вычисленный в программе.Если это так, имеет смысл сделать его константой:
MIN_DISTANCE_BY_LASER = {
blaster: 200,
helium_neon: 180,
nuclear_pumped: 175,
krypton: 170,
co2: 160,
coil: 150,
strontium_vapor: 140,
ruby: 130,
xenon_ion: 120,
free_electron: 110,
gas_dynamic: 95,
nitrogen: 0
}
Мы можем написать метод для возврата нужного лазера следующим образом:
def laser_by_distance(distance)
MIN_DISTANCE_BY_LASER.find { |_,d| distance > d }.first
end
laser_by_distance(43) #=> :nitrogen
laser_by_distance(95) #=> :nitrogen
laser_by_distance(126) #=> :xenon_ion
laser_by_distance(154) #=> :coil
laser_by_distance(170) #=> :co2
laser_by_distance(200) #=> :helium_neon
laser_by_distance(230) #=> :blaster
Интересно, что этот же подход можно использовать для генерации случайных величин из дискретной функции распределения вероятностей.
Если скорость имеет существенное значение (не столько в этой задаче, сколько для задач, гдеколичество элементов [пар] в массиве относительно велико), можно использовать тот факт, что все расстояния в MIN_DISTANCE_BY_LASER
кратны 5
.Идея состоит в том, чтобы избежать линейного поиска в хэше, чтобы найти нужный лазер для заданного расстояния, а вместо этого получить лазер путем вычисления с расстояния смещения в массив лазеров.
arr = MIN_DISTANCE_BY_LASER.to_a.reverse
#=> [[:nitrogen, 0],[:gas_dynamic, 95], [:free_electron, 110],
# [:xenon_ion, 120], [:ruby, 130], [:strontium_vapor, 140],
# [:coil, 150], [:co2, 160], [:krypton, 170],
# [:nuclear_pumped, 175], [:helium_neon, 180], [:blaster, 200]]
LASER_BY_INTERVAL = (1..arr.size-2).
flat_map { |i| [arr[i][0]] * ((arr[i+1][1] - arr[i][1])/5) }
#=> [:gas_dynamic, :gas_dynamic, :gas_dynamic,
# :free_electron, :free_electron,
# :xenon_ion, :xenon_ion,
# :ruby, :ruby,
# :strontium_vapor, :strontium_vapor,
# :coil, :coil,
# :co2, :co2,
# :krypton,
# :nuclear_pumped,
# :helium_neon, :helium_neon, :helium_neon, :helium_neon]
MIN_DST = arr[1][1] #=> 95
MIN_LSR = arr[0][0] #=> :nitrogen
MAX_LSR, MAX_DST = arr[-1]
#=> [:blaster, 200]
Теперь мы можем написать метод.
def laser_by_distance(dst)
case
when dst <= MIN_DST
MIN_LSR
when dst > MAX_DST
MAX_LSR
else
LASER_BY_INTERVAL[(dst-MIN_DST).fdiv(5).ceil - 1]
end
end
laser_by_distance(43) #=> :nitrogen
laser_by_distance(95) #=> :nitrogen
laser_by_distance(126) #=> :xenon_ion
laser_by_distance(154) #=> :coil
laser_by_distance(170) #=> :co2
laser_by_distance(200) #=> :helium_neon
laser_by_distance(230) #=> :blaster
1.В хэше OP оба значения :nuclear_pumped
и :krypton
имели значения 170
.Это проблематично.Например, если расстояние было 169
, неясно, какой из двух лазеров следует использовать.Имеет смысл, что каждый лазер имеет уникальную ценность.Поэтому я изменил :nuclear_pumped
на 175
.