Подтвердить что ты не робот

Rails 3. Как получить разницу между двумя массивами?

Предположим, что у меня есть этот массив с идентификаторами доставки.

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

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

Массив счетов-фактур с идентификатором доставки

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.

4b9b3361

Ответ 1

Сначала вы получите список shipping_id, который отображается в счетах:

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

Затем "отбросить" их из исходного массива:

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

Примечание: помните, что reject возвращает новый массив, используйте reject! если вы хотите изменить исходный массив

Ответ 2

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

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

Ответ 3

Использовать знак-заменитель

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

Ответ 4

Предыдущий ответ здесь из 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

Ответ 5

Это должно сделать это в одном запросе 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

Ответ 6

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, хотя иногда бывает сложно вспомнить.

Это, безусловно, заботится об этом.

Ответ 7

Чистый рубиновый раствор

(a + b) - (a & b)

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

Где a + b создаст объединение между двумя массивами
А А a & b пересечение пересечения
И union - intersection вернет разницу