“ each_cons”如何与个位数一起工作?

时间:2019-01-04 17:11:01

标签: ruby

我一直在做a kata on CodeWars,其摘要是取一个数字,如果数字彼此之间在1之内,则返回"Jumping!!"(例如234543237898)和其他"Not!!"。所有单个数字(例如579)都是跳数。

这是最佳解决方案之一:

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 [原文如此]的工作方式。当true是个数字时,这些方法的条件如何(正确)返回n?连续的是nil0,当在计算中使用时,它们不应返回true,但确实会返回。

3 个答案:

答案 0 :(得分:5)

这是您的误会:

  

连续数为nil或0,在计算中使用时不应返回true(但确实是!)

它既不是nil也不是0。它根本不存在。枚举器为空。

很遗憾,the documentation of 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
#=> []

换句话说:永远不会执行该块,因此,永远不会有错误。

答案 1 :(得分:1)

Jörg回答了您的问题,但这是进行测试的另一种方法。

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!!"

请注意,我使用Integer#digits而非Integer#to_s来分割数字:

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

产生的数组元素的顺序不同,但这与这个问题无关。

Enumerator#peekEnumerator#next导致生成枚举器的最后一个元素之后执行时引发StopInteration异常。 Kernel#loop然后通过打破循环来处理异常。

答案 2 :(得分:0)

另一种可能的解决方案是使用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确实存在。)