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.
Ответы
Ответ 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
вернет разницу