从数组中删除元素 Ruby

70

假设我想要从数组 a = [1,1,1,2,2,3] 中删除元素。如果我执行以下操作:

b = a - [1,3]

然后我会得到:

b = [2,2]

但是,我希望结果是

b = [1,1,2,2]

也就是说,我只想移除被减向量中每个元素的一个实例,而不是所有情况。在 Ruby 中是否有一种简单的方法可以实现这一点?


如果你从 [1,1,3] 中减去,你是想得到 b = [1,2,2] 吗?或者这永远不会发生? - seph
6个回答

82

你可以这样做:

a= [1,1,1,2,2,3]
delete_list = [1,3]
delete_list.each do |del|
    a.delete_at(a.index(del))
end

结果:[1, 1, 2, 2]


1
所以数组减法实际上是不相交集合? - Tetsujin no Oni
1
数组差异---返回一个新的数组,它是原始数组的副本,删除任何也出现在另一个数组中的项(如果您需要类似集合的行为,请参阅库类Set。)[链接](http://www.ruby-doc.org/core-1.9.3/Array.html) - Norm212
2
如果您想删除delete_list中的所有项目,可以执行以下操作。 b = a.each.reject{|x| delete_list.each.include? x} - Archonic
我猜我读错了,但是如果你从a中删除索引1和3,为什么结果不是[1,1,2,3]呢? - daveomcd
2
@moopasta,因为他正在从数组的开头到结尾删除第一个出现的1和3。实际上,他正在调用delete_at函数,该函数将删除a数组中第一个出现的1和3的索引。因此,在这种情况下,他发出了a.delete_at(0)和a.delete_at(4)的命令。 - parreirat

8
[1,3].inject([1,1,1,2,2,3]) do |memo,element|
  memo.tap do |memo|
    i = memo.find_index(e)
    memo.delete_at(i) if i
  end
end

3

虽然不是很简单,但:

a = [1,1,1,2,2,3]
b = a.group_by {|n| n}.each {|k,v| v.pop [1,3].count(k)}.values.flatten
=> [1, 1, 2, 2]

同样处理“减数”中的多个情况:
a = [1,1,1,2,2,3]
b = a.group_by {|n| n}.each {|k,v| v.pop [1,1,3].count(k)}.values.flatten
=> [1, 2, 2]

编辑:这更多是结合了Norm212和我的答案来进行增强,以实现“功能”解决方案。

b = [1,1,3].each.with_object( a ) { |del| a.delete_at( a.index( del ) ) }

如果需要,可以将它放入lambda函数中:

subtract = lambda do |minuend, subtrahend|
  subtrahend.each.with_object( minuend ) { |del| minuend.delete_at( minuend.index( del ) ) }
end

那么:

subtract.call a, [1,1,3]

不,顺序可能会改变。看起来Norm212确实保留了顺序。 - seph

3

我经常使用的简单解决方案:

arr = ['remove me',3,4,2,45]

arr[1..-1]

=> [3,4,2,45]

0
a = [1,1,1,2,2,3]
a.slice!(0) # remove first index
a.slice!(-1) # remove last index
# a = [1,1,2,2] as desired

0
为了提高速度,我会采取以下方法,只需要对两个数组进行一次遍历。这种方法可以保持顺序。首先,我将展示不改变原始数组的代码,然后展示如何轻松修改以改变原始数组。
arr = [1,1,1,2,2,3,1]
removals = [1,3,1]

h = removals.group_by(&:itself).transform_values(&:size)
  #=> {1=>2, 3=>1} 
arr.each_with_object([]) { |n,a|
  h.key?(n) && h[n] > 0 ? (h[n] -= 1) : a << n }
  #=> [1, 2, 2, 1]

arr
  #=> [1, 1, 1, 2, 2, 3, 1] 

如果要改变 arr,请写入:

h = removals.group_by(&:itself).transform_values(&:count)
arr.replace(arr.each_with_object([]) { |n,a|
  h.key?(n) && h[n] > 0 ? (h[n] -= 1) : a << n })
  #=> [1, 2, 2, 1]

arr
  #=> [1, 2, 2, 1]

这里使用了21世纪的方法Hash#transform_values(在MRI v2.4中新增),但也可以写成:

h = Hash[removals.group_by(&:itself).map { |k,v| [k,v.size] }]

或者

h = removals.each_with_object(Hash.new(0)) { | n,h| h[n] += 1 }

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接