Jus*_* L. 10 ruby arrays iterator for-loop enumerable
k = [1,2,3,4,5]
for n in k
puts n
if n == 2
k.delete(n)
end
end
puts k.join(",")
# Result:
# 1
# 2
# 4
# 5
# [1,3,4,5]
# Desired:
# 1
# 2
# 3
# 4
# 5
# [1,3,4,5]
Run Code Online (Sandbox Code Playgroud)
其他数组迭代器,k.each也会发生同样的效果:
k = [1,2,3,4,5]
k.each do |n|
puts n
if n == 2
k.delete(n)
end
end
puts k.join(",")
Run Code Online (Sandbox Code Playgroud)
具有相同的输出.
这种情况发生的原因非常清楚...... Ruby实际上并没有迭代存储在数组中的对象,而只是将它变成一个漂亮的数组索引迭代器,从索引0开始,每次都增加索引直到它结束.但是当你删除一个项目时,它仍然会增加索引,所以它不会两次评估相同的索引,这是我想要的.
这可能不是正在发生的事情,但这是我能想到的最好的.
有干净的方法吗?是否已有可以执行此操作的内置迭代器?或者我是否需要弄脏并执行数组索引迭代器,并且在删除项目时不会增加?(或遍历数组的克隆,并从原始数组中删除)
澄清
我不只是想从数组中删除项目; 对不起,如果那是清楚的.我想要做的是遍历每个元素,并"处理"它; 此过程有时可能会删除它.为了更准确:
class Living_Thing
def initialize tracker,id
@tracker = tracker
@id = id
@tracker << self
end
def process
do_stuff
puts @id
if @id == 2
die
end
end
def die
do_stuff_to_die
@tracker.delete(self)
end
def inspect
@id
end
end
tracking_array = Array.new()
foo = Living_Thing.new(tracking_array,1)
bar = Living_Thing.new(tracking_array,2)
rab = Living_Thing.new(tracking_array,3)
oof = Living_Thing.new(tracking_array,4)
puts tracking_array.join(",") # => [1, 2, 3, 4]
for n in tracking_array
n.process
end
# result: only foo, bar, and oof are processed
Run Code Online (Sandbox Code Playgroud)
理想情况下,我希望处理tracking_array中的所有项目.
当从tracking_array中删除Living_Thing时,必须调用Living_Thing #die ; do_stuff_to_die清理必须被绑定的东西.
Chu*_*uck 15
在迭代它时,在大多数语言中修改集合是一个错误.在大多数语言中,解决方案是创建一个副本并进行变异或构建索引列表,并在完成迭代时对这些索引执行操作,但Ruby的迭代器会为您提供更多.一些解决方案显而易见.最惯用的IMO:
puts k
puts k.reject {|n| n == 2}.join(',')
Run Code Online (Sandbox Code Playgroud)
更直接地从您的示例翻译:
k.delete_if do |n|
puts n
n == 2
end
puts k.join(',')
Run Code Online (Sandbox Code Playgroud)
(delete_if
基本上是破坏性版本reject
,它返回块未返回true的对象数组.)
这可能更适合处理(参考更新的澄清)
k = [1,2,3,4,5]
k.dup.each do |n|
puts n
if n == 2
k.delete(n)
end
end
puts k.join(",")
Run Code Online (Sandbox Code Playgroud)
它回避了您所遇到的问题(关于通过对象迭代与通过索引迭代)
归档时间: |
|
查看次数: |
1072 次 |
最近记录: |