[英]Rails 3. How to get the difference between two arrays?
假设我有这个带有发货 ID 的数组。
s = Shipment.find(:all, :select => "id")
[#<Shipment id: 1>, #<Shipment id: 2>, #<Shipment id: 3>, #<Shipment id: 4>, #<Shipment id: 5>]
带有发货 ID 的发票数组
i = Invoice.find(:all, :select => "id, shipment_id")
[#<Invoice id: 98, shipment_id: 2>, #<Invoice id: 99, shipment_id: 3>]
shipment_id
。要创建发票,我单击“新建发票”,然后有一个带货件的选择菜单,因此我可以选择“我要为哪个货件创建发票”。 因此,我只想显示尚未为其创建发票的发货清单。
所以我需要一系列还没有发票的货件。 在上面的例子中,答案是 1、4、5。
a = [2, 4, 6, 8]
b = [1, 2, 3, 4]
a - b | b - a # => [6, 8, 1, 3]
首先,您将获得发票中出现的 shipping_id 列表:
ids = i.map{|x| x.shipment_id}
然后从原始数组中“拒绝”它们:
s.reject{|x| ids.include? x.id}
注意:记住拒绝返回一个新数组,使用拒绝! 如果要更改原始数组
使用替代符号
irb(main):001:0> [1, 2, 3, 2, 6, 7] - [2, 1]
=> [3, 6, 7]
Ruby 2.6 引入了Array.difference
:
[1, 1, 2, 2, 3, 3, 4, 5 ].difference([1, 2, 4]) #=> [ 3, 3, 5 ]
所以在这里给出的情况下:
Shipment.pluck(:id).difference(Invoice.pluck(:shipment_id))
似乎是这个问题的一个很好的优雅解决方案。 我一直是a - b | b - a
忠实追随者a - b | b - a
a - b | b - a
,虽然有时很难回忆起来。
这当然会照顾到这一点。
纯红宝石溶液是
(a + b) - (a & b)
([1,2,3,4] + [1,3]) - ([1,2,3,4] & [1,3])
=> [2,4]
a + b
将在两个数组之间产生联合
和a & b
返回交集
和union - intersection
将返回差异
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
这应该在一个 ActiveRecord 查询中完成
Shipment.where(["id NOT IN (?)", Invoice.select(:shipment_id)]).select(:id)
它输出 SQL
SELECT "shipments"."id" FROM "shipments" WHERE (id NOT IN (SELECT "invoices"."shipment_id" FROM "invoices"))
在Rails 4+ 中,您可以执行以下操作
Shipment.where.not(id: Invoice.select(:shipment_id).distinct).select(:id)
它输出 SQL
SELECT "shipments"."id" FROM "shipments" WHERE ("shipments"."id" NOT IN (SELECT DISTINCT "invoices"."shipment_id" FROM "invoices"))
而不是select(:id)
我推荐ids
方法。
Shipment.where.not(id: Invoice.select(:shipment_id).distinct).ids
在处理字符串数组时,将差异组合在一起会很有用。
在这种情况下,我们可以使用 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"]
# ]
s.select{|x| !ids.include? x.id}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.