2011-12-26 91 views
32

比方说,我有这个数组与发货ID。发票与货物ID的Rails 3.如何获得两个数组之间的区别?

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

[#<Invoice id: 98, shipment_id: 2>, #<Invoice id: 99, shipment_id: 3>] 
  • 发票

    s = Shipment.find(:all, :select => "id") 
    
    [#<Shipment id: 1>, #<Shipment id: 2>, #<Shipment id: 3>, #<Shipment id: 4>, #<Shipment id: 5>] 
    

    阵列属于装运。

  • 装运有一个发票。
  • 所以发票表有一列shipment_id

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

所以我需要一个没有发票的货件数组呢。在上面的例子中,答案是1,4,5

+1

1,4,5不是具有no_shipment_id的发票的ID列表。 – Robin 2011-12-26 23:28:29

+0

对不起,更正的问题。感谢您考虑它。 – leonel 2011-12-26 23:44:32

+2

[查找所有记录没有关联的记录](http://stackoverflow.com/questions/1314408/finding-all-records-without-associated-ones) – 2011-12-27 00:08:56

回答

34

首先,你将得到的是出现在发票shipping_id的列表:

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

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

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

注:记住,拒绝返回一个新数组,使用拒绝!如果你想改变原有的阵列

+0

如果您使用Rails 3.2.1+和ActiveRecord应该使用pluck:'ids = i.pluck(:id)' – 2014-02-14 11:15:25

+3

这比仅执行'xi'指数式地慢。数组越大,它越慢。这是我写的比较两种方法的基准http://runnable.com/U5Y8g_nsUQokbzNl/benchmark-ruby-array-diff-methods – Ryan 2014-06-09 23:05:04

+0

@Ryan - 是的,但那不是一回事。 – pguardiario 2014-06-10 06:59:20

20

使用替代标志

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

如果你翻转这两个阵列,这将不起作用。 – Trip 2014-02-06 14:46:22

+3

This:'[2,1] - [1,2,3,2,6,7]''返回'[]'。所以它让我很好奇你如何从两个动态数组中获得不同的顺序。 – Trip 2014-02-09 06:31:51

+10

@Trip回答你的问题,你可以做这样的事情......'(a-b)+(b-a)'你可以在这两个数组中获得唯一值,然后将这些值合并成一个数组。 – Ryan 2014-06-09 22:51:56

5

这里从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 
87
a = [2, 4, 6, 8] 
b = [1, 2, 3, 4] 

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

这是最优雅的答案。 'a - b'返回一个不在b中的元素。 'b - a'返回b中不在a和|中的任何元素从这2个结果中返回唯一的一组元素。 – galatians 2015-05-05 19:10:29

+0

喜欢这个:)这种比较数组差异的好方法 – 2015-12-24 18:51:09

+0

伟大的方法,但是,这不会为重复的值工作。例如,如果包含到两个4的第二个4不会显示出来 – 2017-11-07 00:33:44

4

这应做到在一个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