2012-02-10 85 views
3

我有这样的:红宝石环路跳过元素

puts pids 
pids.each do |pid| 
    puts "Running on pid #{pid}" 
    begin 
     Process::kill(0, pid) 
     puts "Pid #{pid} still alive" 
    rescue Errno::ESRCH 
     puts "Pid #{pid} now dead!!!!" 
     pids.delete(pid) 
     running_jobs -= 1 
     puts "Remaining jobs: #{running_jobs}" 
    end 
end 

它输出这样的:

25555 
25579 
25616 
Running on pid 25555 
Pid 25555 now dead!!!! 
Remaining jobs: 2 
Running on pid 25616 
Pid 25616 now dead!!!! 
Remaining jobs: 1  

正如你所看到的,循环从未中间元素上执行。任何人都可以告诉我为什么那样发生?我需要真正地循环每个项目并相应地处理它。

+2

您不想在迭代同一个集合的同时删除集合中的元素。 (我认为这在大多数编程语言中都是正确的。)除了@ klochner关于您特定情况的帖子外,还可以查看这些帖子以了解从Ruby中的数组中删除所选项目的其他方式:http://stackoverflow.com/问题/ 3260686/how-can-i-use-arraydelete-while-iterating-over-the-array http://stackoverflow.com/questions/2933366/deleting-while-iterating-in-ruby – Telemachus 2012-02-10 00:24:45

+0

由于某种原因,我觉得就像我已经能够在我编写的其他程序中做到的那样。我将不得不稍后尝试。我是Ruby的新手,非常感谢帮助。 – jeffcook2150 2012-02-10 00:43:03

回答

6

您在使用pids.delete(pid)进行迭代时突变数组所以,您在位于索引0的25555处,然后将其删除,导致数组看起来像[25579, 25616]。然后你迭代,现在你在索引1,这是25616.如果你只是删除删除,你不会再改变数组,迭代将按预期工作。例如,

3

在遍历它不能发生变异的阵列 - 只要拿出这条线:

pids.delete(pid) 

从你的代码来看,你可能要重构像这样的模拟delete电话:

pids = pids.select do |pid| 
    puts "Running on pid #{pid}" 
    begin 
     Process::kill(0, pid) 
     puts "Pid #{pid} still alive" 
     true 
    rescue Errno::ESRCH 
     puts "Pid #{pid} now dead!!!!" 
     running_jobs -= 1 
     puts "Remaining jobs: #{running_jobs}" 
     false 
    end 
end 
+0

为什么会导致某些项目被跳过?它应该只是从阵列中删除当前的PID。我想让这个数组成为我试图追踪的pid的最新列表,我不想让一堆死体重在那里漂浮。 – jeffcook2150 2012-02-10 00:22:59

4

因此,您的循环在项目5上,并将其删除。项目6,7等向上移动1,当你的循环去到项目6曾经是的地方时,它找到项目7.

但是说你不能在迭代时改变你的数组有点不稳定。如果您只是用reverse_each替换each,您可以完全保留您的代码。这从头到尾循环访问数组,所以现在当你删除第5项时,6个向上移动并不重要,因为你接下来要4,而且这还没有改变。

+0

太棒了,解决了我的问题。 – Nic 2012-07-30 01:22:40