簡體   English   中英

Rails 3. 如何獲取兩個數組之間的差異?

[英]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。
  • 貨件有一張發票。
  • 所以invoices 表有一列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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM