2011-12-26 7 views
32

Digamos que tengo esta matriz con identificaciones de envíos.Rieles 3. ¿Cómo obtener la diferencia entre dos matrices?

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

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

matriz de facturas con

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

[#<Invoice id: 98, shipment_id: 2>, #<Invoice id: 99, shipment_id: 3>] 
  • facturas de id cargamento pertenece envío.
  • El envío tiene una factura.
  • Entonces, la tabla de facturas tiene una columna de shipment_id.

Para crear una factura, hago clic en New Invoice, luego hay un menú de selección con Envíos, para que pueda elegir "para qué envío estoy creando la factura". Entonces, solo quiero mostrar una lista de envíos para los que no se ha creado una factura.

Por lo tanto, necesito una serie de Envíos que aún no tienen Factura. En el ejemplo anterior, la respuesta sería 1, 4, 5.

+1

1, 4, 5 no es una lista de identificadores de facturas con no_shipment_id. – Robin

+0

Lo sentimos, la pregunta corregida. Gracias por considerarlo – leonel

+2

posible duplicado de [Búsqueda de todos los registros sin asociados] (http://stackoverflow.com/questions/1314408/finding-all-records-without-associated-ones) –

Respuesta

34

En primer lugar se podrían obtener una lista de de shipping_id que aparecen en las facturas:

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

Entonces 'rechazar' desde su matriz original:

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

Nota: recordar que rechazan devuelve una nueva matriz, utilice rechazar! Si desea cambiar la matriz original

+0

Si está utilizando Rails 3.2.1+ y ActiveRecord usted debería usar desplume: 'ids = i.pluck (: id)' –

+3

Esto es exponencialmente más lento que solo hacer 'xi'. Cuanto más grandes sean las matrices, más lento se vuelve. Aquí hay un punto de referencia que escribí comparando los dos métodos: http://runnable.com/U5Y8g_nsUQokbzNl/benchmark-ruby-array-diff-methods – Ryan

+0

@Ryan: sí, pero eso no es lo mismo. – pguardiario

20

signo Uso sustituto

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

Eso no funcionaría si volteara esas dos matrices. – Trip

+3

Esto: '[2, 1] - [1, 2, 3, 2, 6, 7]' devuelve '[]'. Así que me da curiosidad cómo podría obtener la diferencia de dos matrices dinámicas, independientemente de su orden. – Trip

+10

@Trip para responder a su pregunta, podría hacer algo como esto ... '(a-b) + (b-a)' donde obtiene los valores únicos en ambas matrices, luego combina esos valores en una sola matriz. – Ryan

5

La respuesta anterior aquí desde pgquardiario sólo incluyó una diferencia direccional. Si desea la diferencia entre ambas matrices (ya que ambas tienen un elemento único), intente algo como lo siguiente.

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

Esta es la respuesta más elegante. 'a - b' devuelve cualquier elemento en a que no esté en b. 'b - a' devuelve cualquier elemento en b que no esté en a y | devuelve el conjunto único de elementos de esos 2 resultados. – galatians

+0

Me encanta esto :) Una buena manera de comparar las diferencias de matriz –

+0

Gran enfoque, sin embargo, esto no funcionará para valores duplicados. Por ejemplo, si se incluye a dos 4, el segundo 4 no aparecería –

4

Esto debe hacerlo en una consulta ActiveRecord

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

Y da salida al SQL

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

En rieles 4+ que puede hacer el siguiendo

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

Y da salida al SQL

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

Y en vez de select(:id) recomiendo el método ids.

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