Уникальные объекты в сгруппированном хэше
У меня есть хеш, созданный .group_by
метод, со строками в качестве ключей и объектами AR в качестве значений. И я хочу избавиться от объектов AR с дублированным полем (другие поля могут или не могут быть одинаковыми).
Чтобы прояснить вопрос, я создал этот фрагмент:
require 'ostruct'
def os_new(fid); OpenStruct.new(fid: fid, rand: rand(100)); end
a = [os_new(1), os_new(2), os_new(3)]
b = [os_new(3), os_new(3), os_new(2)]
c = [os_new(5), os_new(5), os_new(5), os_new(5)]
grouped_hash = { a: a, b: b, c: c}
grouped_hash
вот это:
# {:a=>[#<OpenStruct fid=1, rand=7>, #<OpenStruct fid=2, rand=50>, #<OpenStruct fid=3, rand=13>],
# :b=>[#<OpenStruct fid=3, rand=51>, #<OpenStruct fid=3, rand=58>, #<OpenStruct fid=2, rand=88>],
# :c=>[#<OpenStruct fid=5, rand=40>, #<OpenStruct fid=5, rand=8>, #<OpenStruct fid=5, rand=45>, #<OpenStruct fid=5, rand=72>]}
Теперь в результате я хочу хэш с уникальным fid
s для каждого ключа:
# {:a=>[#<OpenStruct fid=1, rand=7>, #<OpenStruct fid=2, rand=50>, #<OpenStruct fid=3, rand=13>],
# :b=>[#<OpenStruct fid=3, rand=51>, #<OpenStruct fid=2, rand=88>],
# :c=>[#<OpenStruct fid=5, rand=40>]}
Мое решение требует нескольких действий и выглядит некрасиво.
grouped_hash.each_value do |value|
fids = []
value.delete_if do |object|
if fids.include? object.fid
true
else
fids << object.fid
false
end
end
end
Я ищу наиболее элегантный (возможно, 1-строчный) и эффективный способ (без пересоздания хеша).
3 ответа
grouped_hash.each_value(&:uniq)
Согласно объектам AR, Rails сознательно делегирует проверки на равенство в столбец идентификаторов. Если вы хотите знать, что два объекта AR содержат одинаковые значения, сравните результат вызова #attributes для обоих.
Не совсем однострочный (хотя вы также можете написать его одной строкой):
grouped_hash.inject({}) do |hash, element|
hash[element.first] = element.last.uniq(&:fid)
hash
end