Как `each_cons` работает с однозначными числами? - PullRequest
0 голосов
/ 04 января 2019

Я делал ката на CodeWars , сводка которого состоит в том, чтобы взять число и вернуть "Jumping!!", если цифры находятся в пределах 1 друг от друга (например, 2345, 4323, 7898) и "Not!!" в противном случае. Все однозначные числа (например, 5, 7, 9) являются прыгающими числами.

Это одно из лучших решений:

def jumping_number(n)
    n.to_s.chars.map(&:to_i).each_cons(2).all? { |x, y| (x - y).abs == 1 } ? "Jumping!!" : "Not!!"
end

Это мой собственный код:

def jumping_number(n)
    n.to_s.chars.map(&:to_i).each_cons(2) { |x, y| return "Not!!" if (x - y).abs != 1 }
    return "Jumping!!"
end

Я не понимаю, как работает each_con [sic]. Как условие этих методов (правильно) может вернуть true, если n - это одна цифра? Последовательность - это либо nil, либо 0, которая при использовании в вычислениях не должна возвращать true, и все же она возвращает.

Ответы [ 3 ]

0 голосов
/ 04 января 2019

Йорг ответил на ваш вопрос, но вот еще один способ выполнить тест.

def jumping_number(n)
  enum = n.digits.to_enum
  loop { return "Not!!" unless (enum.next - enum.peek).abs == 1 }
  "Jumping!!"
end     

jumping_number 5      #=> "Jumping!!" 
jumping_number 12321  #=> "Jumping!!" 
jumping_number 1243   #=> "Not!!"

Обратите внимание, что я использовал Целое число # цифр вместо Целое число # to_s для разделения цифр:

123.digits                 #=> [3, 2, 1] 
123.to_s.chars.map(&:to_i) #=> [1, 2, 3]

Порядок элементов создаваемого массива не одинаков, но это не имеет значения для этой проблемы.

Enumerator # peek вызывает исключение StopInteration, когда оно выполняется после того, как Enumerator # next вызвал генерацию последнего элемента перечислителя. Kernel # loop затем обрабатывает исключение, прерывая цикл.

0 голосов
/ 05 января 2019

Другое возможное решение - использовать Enumerable#chunk_while, а затем измерять размер возвращаемого массива. Как это работает:

[1,2,3].chunk_while{ |x, y| (x-y).abs == 1 }.to_a #=> [[1, 2, 3]]
[1].chunk_while{ |x, y| (x-y).abs == 1 }.to_a #=> [[1]]
[1,2,4].chunk_while{ |x, y| (x-y).abs == 1 }.to_a #=> [[1, 2], [4]]

Итак, используя его в методе:

def jumping_number(n)
  n.digits.chunk_while{ |x, y| (x-y).abs == 1 }.to_a.size == 1 ? "Jumping!!" : "Not!!"
end

(Спасибо @Cary Swoveland за то, что вспомнили, что Integer#digits существует.)

0 голосов
/ 04 января 2019

Вот ваше недоразумение:

Последовательность равна нулю или 0, что при использовании в вычислениях не должно возвращать истину (и все же это так!)

Это ни nil, ни 0. Его просто не существует вообще. Перечислитель пуст.

К сожалению, это не задокументировано в документации Enumerable#each_cons. Решение вашей головоломки состоит в том, что если запрашиваемый вами размер минусов меньше размера перечисляемого, то минусов не будет:

[5, 6, 7].each_cons(2).to_a
#=> [[5, 6], [6, 7]]

[5, 6, 7].each_cons(3).to_a
#=> [5, 6, 7]

[5, 6, 7].each_cons(4).to_a
#=> []

Другими словами: блок никогда не выполняется, поэтому никогда не будет ошибки.

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