Ruby循环跳过元素

时间:2012-02-10 00:17:31

标签: ruby

我有这个:

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    

如您所见,循环永远不会在中间元素上执行。谁能告诉我为什么会这样?我需要真正遍历每个项目并相应地处理它。

3 个答案:

答案 0 :(得分:6)

当您使用pids.delete(pid)迭代数组时,您正在改变数组。因此,您在索引0处于25555,然后删除它,导致数组看起来像[25579, 25616]。然后你迭代,现在你在索引1,这是25616.如果你只是删除删除,你将不再改变数组,迭代将按预期工作。

答案 1 :(得分:4)

例如,你的循环在第5项,你删除它。第6,7项等向上移动1,当你的循环移动到第6项时,它会找到第7项。

但是说你在迭代它时不能改变你的数组有点笨拙。如果只是将each替换为reverse_each,则可以完全按照自己的方式保存代码。这会从头到尾遍历数组,所以现在当你删除第5项时,6向上移动并不重要,因为你接下来要4,而且还没有改变(还有)。

答案 2 :(得分: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