我有一个数组:
arr = [7, 8, 9, 10, 11, 13, 14, 15, 16, 17, 19, 20, 21, 22, 23]
我想通过在-5的每一步删除来修改我的数组,即删除后arr[-5], arr[-10], arr[-15]
的原始数组arr
等于:
arr = [8, 9, 10, 11, 14, 15, 16, 17, 20, 21, 22, 23]
我被告知从您正在迭代的数组中删除它不是一个好习惯。有没有干净的解决方案?
我有一个数组:
arr = [7, 8, 9, 10, 11, 13, 14, 15, 16, 17, 19, 20, 21, 22, 23]
我想通过在-5的每一步删除来修改我的数组,即删除后arr[-5], arr[-10], arr[-15]
的原始数组arr
等于:
arr = [8, 9, 10, 11, 14, 15, 16, 17, 20, 21, 22, 23]
我被告知从您正在迭代的数组中删除它不是一个好习惯。有没有干净的解决方案?
只是对@tihom答案的修改,不依赖于唯一性,而是使用“如何在 Ruby 中使用索引映射?”中的一些想法。:
>> arr.each_with_index.select{ |x, i| (arr.count-i)%5 != 0 }.map{ |x,i| x }
=> [8, 9, 10, 11, 14, 15, 16, 17, 20, 21, 22, 23]
一步一步地做:
.each_with_index
返回一个枚举器,它产生成对的值及其索引,如[7, 0], [8, 1], [9, 2], ...
.select{...}
选择那些不能被 5 整除的对[x,i]
(count - i
除了,count - 5
等count - 10
).map{ |x,i| x }
将每一对转换为其第一个元素。我认为不是最有效的,但至少很清楚
奖金:
我确信通过一些转换(以功能样式)创建一个新数组比就地修改它更好,但是如果你坚持“就地”,这里是@sawa答案的修改没有硬编码的数字:
>> (-arr.count..-5).select {|i| i % 5 == 0}.each{|i| arr.delete_at(i)}
=> [-15, -10, -5]
>> arr
=> [8, 9, 10, 11, 14, 15, 16, 17, 20, 21, 22, 23]
这里我们有一个从 -size 到 -5 的范围,只选择能被 5 整除的索引,然后被它们删除。正如他所说,在这里按此顺序准确删除很重要。但仍然为了保护自己免受可能的错误,我认为永远不要从正在迭代的数组中删除而是生成一个新数组(如第一种方法)更安全。为什么复杂?;)
这是一个简单的解决方案:
p arr.reverse.each_slice(5).map{|x|x[0..-2]}.flatten.reverse
# => [8, 9, 10, 11, 14, 15, 16, 17, 20, 21, 22, 23]
arr.reject.with_index{|x,i| (i-arr.count) % 5 == 0 }
=> [8, 9, 10, 11, 14, 15, 16, 17, 20, 21, 22, 23]
基于答案https://stackoverflow.com/a/19317883/908515:
arr.reverse.reject.with_index { | _, i | (i + 1) % 5 == 0 }.reverse
# i.e. arr.reverse.drop_every(5).reverse
如果要就地修改原始数组,可以这样做
arr.reverse!.reject!.with_index { | _, i | (i + 1) % 5 == 0 }.reverse!
这是安全的,因为枚举i
器索引 ( ) 独立于数组索引。
从索引计数的同一侧迭代时修改数组很复杂。换句话说,当你有正索引时,你不应该在修改时从头到尾迭代;如果您有负索引,则不应从尾部迭代到头部。否则,没有问题。
由于您有负指数,因此从头部向尾部进行修改至关重要。
[-15, -10, -5].each{|i| arr.delete_at(i)}
# => [8, 9, 10, 11, 14, 15, 16, 17, 20, 21, 22, 23]