从数组中删除多个值范围

时间:2016-08-03 17:55:53

标签: ruby-on-rails arrays ruby range

a1 = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20]
a2 = [2..4, 8..11, 16..17]

可以从数组中删除一系列值like this

[1, 2, 3, 4, 5, 6, 7, 8, 9].slice!(2..5)

迭代范围并应用上述相同(a2.each { |range| a1.slice!(range) })并不完美。范围有时会重叠,从而破坏其他范围的引用索引。

那么,有关如何以最有效的方式从a2中移除a1中的范围的任何建议? a1通常为[* 0..10080]。 a2有大约30个范围,每个范围包含数百个值。

4 个答案:

答案 0 :(得分:1)

如果第一次操作的结果影响第二次操作,你或者要跟踪产生的偏移影响,这可能会变得疯狂复杂,或者只是进行反向操作,而是标记你想要的或者不想使用范围:

require 'set'

a1 = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20]
a2 = [2..4, 8..11, 16..17]

# Convert the ranges to a set of index values to remove
reject = Set.new(a2.flat_map(&:to_a))

# Using value/index pairs, accumulate those values which are
# not being excluded by their index.
a1.each_with_index.each_with_object([ ]) do |(v, i), a|
  a << v unless (reject.include?(i))
end

# => [0, 1, 5, 6, 7, 12, 13, 14, 15, 18, 19, 20]

答案 1 :(得分:0)

我不确定这是最不天真的解决方案,但将您的范围转换为数组似乎很简单,因此您需要处理类似的问题:

a2.each{ |a| a1 = a1 - a.to_a }

答案 2 :(得分:0)

[-1, *a2.flat_map(&:minmax), a1.length].each_slice(2).flat_map{|i,j| a1[i+1...j]}
# => [0, 1, 5, 6, 7, 12, 13, 14, 15, 18, 19, 20] 

答案 3 :(得分:0)

a1 = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20]
a2 = [2..4, 8..11, 16..17]

a1 - a2.flat_map(&:to_a)