在Ruby中从一个数组中减去另一个数组

92

我有两个Task数组 - created和assigned。我想从created任务数组中移除所有已分配的任务。 这是我的工作代码,虽然有点凌乱:

    @assigned_tasks = @user.assigned_tasks
    @created_tasks = @user.created_tasks

    #Do not show created tasks assigned to self
    @created_not_doing_tasks = Array.new
    @created_tasks.each do |task|
        unless @assigned_tasks.include?(task)
            @created_not_doing_tasks << task
        end
    end

我相信有更好的方法,那是什么?谢谢 :-)


我敢打赌,在代码底层,答案正在执行你所编写的操作。 - baash05
2个回答

189

你可以在Ruby中进行数组减法:

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

ary - other_ary → new_ary 数组差集

返回一个新的数组,它是原始数组的副本,移除了在 other_ary 中也出现的任何项。顺序保持与原始数组相同。

它使用元素的哈希和 eql? 方法进行比较以提高效率。

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

如果您需要类似于集合的行为,请参见库类 Set。

请参考Array文档。


2
糟糕,我真是个大笨蛋。由于某种原因我以为这对对象行不通。 结果运行得非常好-谢谢! - doctororange
32
请谨慎操作,先在IRB中进行测试,例如:[5, 5, 5, 5] - [5, 5] = [] ... 减法会删除数组中的唯一元素。 - hagope
9
请注意,这个不会成功:[1,2]-[1,2,3] => []。但是[1,2,3]-[1,2] => [3]。唉。 - Zabba
19
如果你从“减法”的角度考虑,那么这些“陷阱”就会变得容易理解。当你进行“减法”运算时,你不是要求计算出两个数的差异...而是在询问将Y从X中减去后的结果...如果Y中有一些X中没有的元素,那么结果就有点“未定义”,因此额外的Y元素不会被包括在X的结果中。 - Bane
2
具体来说,Array#- 是一个集合差。它更像是 Array#| 的反操作,即集合并,而不是 Array#+,即连接(根本不是一个集合操作!)。 - ymbirtt
显示剩余3条评论

14

以上解决方案

a - b

从数组a中删除所有在数组b中出现的元素。

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

有些情况下,您希望结果为 [1, 2, 3, 3, 5]。也就是说,您不想删除所有重复项,而只想逐个删除元素。

您可以通过以下方式实现

class Array
  def delete_elements_in(ary)
    ary.each do |x|
      if index = index(x)
        delete_at(index)
      end
    end
  end
end

测试

irb(main):198:0> a = [ 1, 1, 2, 2, 3, 3, 4, 5 ]
=> [1, 1, 2, 2, 3, 3, 4, 5]
irb(main):199:0> b = [ 1, 2, 4 ]
=> [1, 2, 4]
irb(main):200:0> a.delete_elements_in(b)
=> [1, 2, 4]
irb(main):201:0> a
=> [1, 2, 3, 3, 5]

即使这两个数组没有排序,代码也可以起作用。在本例中,这两个数组是有序的,但这并不是必需的。


delete_elements_in 在 Ruby 正式版中不可用(ruby 2.6.3p62)。 - qaisjp
2
@qaisjp,因为它是由作者定义的。你也应该去定义它。看看测试代码上面的代码。 - ismailarilik

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