Как создать цикл .each для захвата ключа и значения из хеша на основе пользовательского ввода? - PullRequest
0 голосов
/ 09 мая 2019

Я создал хэш различных типов лазеров для использования в зависимости от расстояния до объекта.Я хочу спросить пользователя, как далеко он находится от нужного объекта, и затем дать ему лазер, который он должен использовать, основываясь на вводе пользователя.

Я пытаюсь реализовать метод .each, чтобы яМожно перебрать хеш и выяснить, где в хэше должен находиться пользовательский ввод, но я изо всех сил пытаюсь реализовать эту концепцию в коде.Бонус, если вы научите меня выполнять мой ответ, используя .gsub ("_", "")

laserType = {
  blaster: 200,
  helium_neon: 180,
  nuclear_pumped: 170,
  krypton: 170,
  co2: 160,
  coil: 150,
  strontium_vapor: 140,
  ruby: 130,
  xenon_ion: 120,
  free_electron: 110,
  gas_dynamic: 95,
  nitrogen: 0
}

sortedLasers = laserType.sort_by { |name, range| range }


puts "How far away from the object are you?"
answer = gets.chomp

sortedLasers.each {|name, range| puts "#{key} is #{value}"};

EX:

"Как далеко от объекта вы находитесь?"

"165"

"Вы должны использовать лазер со2!"

Ответы [ 3 ]

1 голос
/ 09 мая 2019

Вы можете использовать find:

answer = 120
laser = laserType.find { |type, distance| distance == answer }
# => [:xenon_ion, 120]

puts "Try using a #{laser.first.to_s.tr("_", " ")} laser."

Если вы хотите сопоставить несколько лазеров, вместо find вы бы использовали select, который будет возвращать массив всех совпадающих значений:

matches = laserType.select { |_, distance| distance == answer }
puts "Try using one of these: " + matches.map { |type, _| type.to_s.tr("_", " ") }.join(", ")

Вы можете улучшить это, используя диапазон (10..15), чтобы учесть диапазон расстояний:

laser_types = {
  blaster: 190..210,
  helium_neon: 170..190,
  free_electron: 70..150,
  nitrogen: 0..50,
}

laser_types.select { |_, range| range.cover?(answer) }
0 голосов
/ 09 мая 2019

Если вы хотите найти лазер, максимальный диапазон которого ближе всего к вводу пользователя, но не меньше этого, тогда

laser_name = laser_types.each.lazy
  .select{|name, range| range >= answer}
  .min_by{|name, range| range}[0]
0 голосов
/ 09 мая 2019

Я предполагаю, что отображение расстояний до лазеров - это данные, а не хеш, вычисленный в программе.Если это так, имеет смысл сделать его константой:

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.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...