Ruby数组减法,不会多次删除项目

Ruby中的规范数组差异示例是:

[ 1, 1, 2, 2, 3, 3, 4, 5 ] - [ 1, 2, 4 ] #=> [ 3, 3, 5 ] 

取而代之的是获得以下行为的最佳方法是什么?

 [ 1, 1, 2, 2, 3, 3, 4, 5 ].subtract_once([ 1, 2, 4 ]) #=> [ 1, 2, 3, 3, 5 ] 

也就是说,只从第一个数组中删除第二个数组中每个匹配项的第一个实例。

减去它们在其他数组或任何Enumerable中出现的次数:

 class Array # Subtract each passed value once: # %w(1 2 3 1).subtract_once %w(1 1 2) # => ["3"] # [ 1, 1, 2, 2, 3, 3, 4, 5 ].subtract_once([ 1, 2, 4 ]) => [1, 2, 3, 3, 5] # Time complexity of O(n + m) def subtract_once(values) counts = values.inject(Hash.new(0)) { |h, v| h[v] += 1; h } reject { |e| counts[e] -= 1 unless counts[e].zero? } end 

减去每个唯一值一次:

 require 'set' class Array # Subtract each unique value once: # %w(1 2 2).subtract_once_uniq %w(1 2 2) # => [2] # Time complexity of O((n + m) * log m) def subtract_once_uniq(values) # note that set is implemented values_set = Set.new values.to_a reject { |e| values_set.delete(e) if values_set.include?(e) } end end 
 class Array def subtract_once(b) h = b.inject({}) {|memo, v| memo[v] ||= 0; memo[v] += 1; memo } reject { |e| h.include?(e) && (h[e] -= 1) >= 0 } end end 

我相信这就是我想要的。 非常感谢@glebm

到目前为止,这是我能想到的全部内容:

 [1, 2, 4].each { |x| ary.delete_at ary.index(x) } 

类似于@Jeremy Ruten的答案,但考虑到某些元素可能不存在的事实:

 # remove each element of y from x exactly once def array_difference(x, y) ret = x.dup y.each do |element| if index = ret.index(element) ret.delete_at(index) end end ret end 

此答案也不会在操作时修改原始数组,因此:

 x = [1,2,3] y = [3,4,5] z = array_difference(x, y) # => [1,2] x == [1,2,3] # => [1,2,3]