Ruby-on-rails Rails 3. 如何获取两个数组之间的差异?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/8639857/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-03 02:31:53  来源:igfitidea点击:

Rails 3. How to get the difference between two arrays?

ruby-on-railsrubyarrays

提问by leonel

Let's say I have this array with shipments ids.

假设我有这个带有发货 ID 的数组。

s = Shipment.find(:all, :select => "id")

[#<Shipment id: 1>, #<Shipment id: 2>, #<Shipment id: 3>, #<Shipment id: 4>, #<Shipment id: 5>]

Array of invoices with shipment id's

带有发货 ID 的发票数组

i = Invoice.find(:all, :select => "id, shipment_id")

[#<Invoice id: 98, shipment_id: 2>, #<Invoice id: 99, shipment_id: 3>]
  • Invoices belongs to Shipment.
  • Shipment has one Invoice.
  • So the invoices table has a column of shipment_id.
  • 发票属于Shipment。
  • 货件有一张发票。
  • 因此发票表有一列shipment_id.

To create an invoice, I click on New Invoice, then there is a select menu with Shipments, so I can choose "which shipment am i creating the invoice for". So I only want to display a list of shipments that an invoice hasn't been created for.

要创建发票,我单击“新建发票”,然后有一个带货件的选择菜单,因此我可以选择“我要为哪个货件创建发票”。因此,我只想显示尚未为其创建发票的发货清单。

So I need an array of Shipments that don't have an Invoice yet. In the example above, the answer would be 1, 4, 5.

所以我需要一系列还没有发票的货件。在上面的例子中,答案是 1、4、5。

采纳答案by pguardiario

First you would get a list of shipping_id's that appear in invoices:

首先,您将获得发票中出现的 shipping_id 列表:

ids = i.map{|x| x.shipment_id}

Then 'reject' them from your original array:

然后从原始数组中“拒绝”它们:

s.reject{|x| ids.include? x.id}

Note:remember that reject returns a new array, use reject! if you want to change the original array

注意:记住拒绝返回一个新数组,使用拒绝!如果要更改原始数组

回答by Kyle Decot

a = [2, 4, 6, 8]
b = [1, 2, 3, 4]

a - b | b - a # => [6, 8, 1, 3]

回答by denis.peplin

Use substitute sign

使用替代符号

irb(main):001:0> [1, 2, 3, 2, 6, 7] - [2, 1]
=> [3, 6, 7]

回答by SRack

Ruby 2.6 is introducing Array.difference:

Ruby 2.6 引入Array.difference

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

So in the case given here:

所以在这里给出的情况下:

Shipment.pluck(:id).difference(Invoice.pluck(:shipment_id))

Seems a nice elegant solution to the problem. I've been a keen follower of a - b | b - a, though it can be tricky to recall at times.

似乎是这个问题的一个很好的优雅解决方案。我一直是 的忠实追随者a - b | b - a,尽管有时很难回忆起来。

This certainly takes care of that.

这当然会照顾到这一点。

回答by 6ft Dan

This should do it in one ActiveRecord query

这应该在一个 ActiveRecord 查询中完成

Shipment.where(["id NOT IN (?)", Invoice.select(:shipment_id)]).select(:id)

And it outputs the SQL

它输出 SQL

SELECT "shipments"."id" FROM "shipments"  WHERE (id NOT IN (SELECT "invoices"."shipment_id" FROM "invoices"))


In Rails 4+you can do the following

Rails 4+ 中,您可以执行以下操作

Shipment.where.not(id: Invoice.select(:shipment_id).distinct).select(:id)

And it outputs the SQL

它输出 SQL

SELECT "shipments"."id" FROM "shipments"  WHERE ("shipments"."id" NOT IN (SELECT DISTINCT "invoices"."shipment_id" FROM "invoices"))

And instead of select(:id)I recommend the idsmethod.

而不是select(:id)我推荐的ids方法。

Shipment.where.not(id: Invoice.select(:shipment_id).distinct).ids

回答by 6ft Dan

The previous answer here from pgquardiario only included a one directional difference. If you want the difference from both arrays (as in they both have a unique item) then try something like the following.

pgquardiario 的上一个答案仅包含一个方向差异。如果您想要两个数组的差异(因为它们都有一个唯一的项目),请尝试以下操作。

def diff(x,y)
  o = x
  x = x.reject{|a| if y.include?(a); a end }
  y = y.reject{|a| if o.include?(a); a end }
  x | y
end

回答by zhisme

Pure ruby solution is

纯红宝石溶液是

(a + b) - (a & b)

(a + b) - (a & b)

([1,2,3,4] + [1,3]) - ([1,2,3,4] & [1,3])
=> [2,4]

Where a + bwill produce a union between two arrays
And a & breturn intersection
And union - intersectionwill return difference

哪里a + b会产生两个阵列之间的联合
a & b回报交集
union - intersection会返回差异

回答by pdobb

When dealing with arrays of Strings, it can be useful to keep the differences grouped together.

在处理字符串数组时,将差异组合在一起会很有用。

In which case, we can use Array#zip to group the elements together and then use a block to decide what to do with the grouped elements (Array).

在这种情况下,我们可以使用 Array#zip 将元素组合在一起,然后使用块来决定如何处理分组的元素(数组)。

a = ["One", "Two",     "Three", "Four"]
b = ["One", "Not Two", "Three", "For" ]

mismatches = []
a.zip(b) do |array| 
  mismatches << array if array.first != array.last
end

mismatches
# => [
#   ["Two", "Not Two"], 
#   ["Four", "For"]
# ]

回答by Fez Abbas

s.select{|x| !ids.include? x.id}