从Ruby中的列表中删除/删除备用号码

时间:2018-06-08 09:46:52

标签: ruby

我有一个问题陈述,即10个人的椅子排成一个圆圈的情况。有一种跳过一个人并要求下一个人离开的模式(从列表中的第一个人开始)。比方说,10人在圈数为1到10的人被要求按此顺序离开1,3,5,7,9,2,6,108。因此,人4是赢家。

获得预期结果的方法是什么?我尝试使用10个元素的数组和这样的编程,

arr = [1,2,3,4,5,6,7,8,9,10]

arr = arr.each_slice(2).map(&:second)

并再次对返回的结果做同样的操作,直到我得到一个元素,但是我没有得到预期的结果。例如;

arr.each_slice(2).map(&:second)
=> [2, 4, 6, 8, 10]
[2, 4, 6, 8, 10].each_slice(2).map(&:second)
=> [4, 8, nil]
[4, 8, nil].each_slice(2).map(&:second)
=>[8, nil]

在这种情况下,输出是,但我期待4.是否有一些更简单的方法来做到这一点并获得所需的输出?

3 个答案:

答案 0 :(得分:8)

只有当arr.size是2的幂时,您的解决方案才有效。例如,在第二步中,您将得到:

[2, 4, 6, 8, 10].each_slice(2).to_a #=> [[2, 4], [6, 8], [10]]

这是nil来自的地方:因为[10].second == nil

此外,逻辑是有缺陷的:在循环的下一次迭代中,它是需要离开的第二个人,而不是第一个。

您需要做的是跟踪下一个人离开的情况?"作为数组索引的一个单独关注点。

这是一个可能的解决方案:

arr = [1,2,3,4,5,6,7,8,9,10]
should_delete = [true, false].cycle
while(arr.size > 1)
  arr.delete_if { should_delete.next }
end

p arr #=> [4]

[true, false].cycle创建了一个[true, false, true, false, true, .....]的无限枚举器。因此,当我们遍历数组时,我们会跟踪下一个人是否必须离开此变量。

旁注:这是一个着名的谜题,称为Josephus problem。我推荐this video作为一个很好的解释。你实际上可以确定"胜利者"通过一个简单的公式,而不是像那样循环遍历数组!

答案 1 :(得分:6)

当椅子排成一个圆圈时,您可以执行以下操作:

  • 拿出列表中的第一把椅子扔出去
  • 旋转圆圈(将第一把椅子移动到列表的末尾,基本上是跳过它)
  • 重复,直到只有一个座位

在代码中:

Error in € (index 9)

答案 2 :(得分:1)

def last_person_standing(arr)
  (arr.size-1).times.reduce(arr) { |a,_| a << a.shift(2).last }.first
end

接下来几点。

  • 如果数组包含n个元素,则会有n-1个步骤,每个步骤都会删除该数组的一个元素;
  • 使用Enumerable#reduce(又名inject),无需在末尾添加一行来返回所需的值;
  • 避免使用arr变异reduce替换arr的参数(arr.dup);
  • a << a.shift(2).last删除数组a的前两个元素,并将第二个元素追加到a的末尾;
  • 我已将.first添加到操作行的末尾以返回剩余的元素而不是包含该单个元素的数组,因为它似乎更有用;和
  • 应添加
  • 代码以处理arr.size < 2
  • 的情况

试试吧。

last_person_standing %w| Agnes Billy-Bob Trixy Bubba Wanda |
   #=> "Billy-Bob"

更多示例如下。

(2..10).each do |n|
   a = [*1..n]
   puts "#{ a }: #{ last_person_standing(a) }"
end

打印

[1, 2]: 2
[1, 2, 3]: 2
[1, 2, 3, 4]: 4
[1, 2, 3, 4, 5]: 2
[1, 2, 3, 4, 5, 6]: 4
[1, 2, 3, 4, 5, 6, 7]: 6
[1, 2, 3, 4, 5, 6, 7, 8]: 8
[1, 2, 3, 4, 5, 6, 7, 8, 9]: 2
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]: 4

这是另一种方式。

def last_person_standing(arr)
  while arr.size > 1
    odd = arr.size.odd?
    arr.pop if odd
    arr.delete_if.with_index { |_,i| i.even? }
    arr.unshift(nil) if odd
  end
  arr.first
end

如果在arr的每轮删除后,如果arr.size为奇数,则弹出arr的最后一个元素,删除带有偶数索引的arr元素然后在unshift的开头nil arr任何占位符对象(我选择了arr.size)(将在下一个周期删除);如果arr甚至只是使用偶数索引从"2","1","3","16","8","3","4","1","2"中删除元素。