Uniq атрибутом объекта в Ruby

В качестве альтернативы вы также можете использовать filter с выражением лямбда для получения желаемого результата. Например:

>>> l1 = [1,2,6,8]
>>> l2 = set([2,3,5,8])

#     v  `filter` returns the a iterator object. Here I'm type-casting 
#     v  it to `list` in order to display the resultant value
>>> list(filter(lambda x: x not in l2, l1))
[1, 6]

Сравнение производительности

Здесь я сравниваю производительность всех ответов, упомянутых здесь. Как и ожидалось, операция Arkku set выполняется быстрее.

PS: set не поддерживают порядок и удаляют дубликат элементов из списка. Следовательно, не используйте разницу в настройках , если вам нужно какое-либо из них.

117
задан Laurie Young 22 September 2008 в 10:21
поделиться

7 ответов

Теперь, если можно отсортировать на значениях атрибута, это может быть сделано:

class A
  attr_accessor :val
  def initialize(v); self.val = v; end
end

objs = [1,2,6,3,7,7,8,2,8].map{|i| A.new(i)}

objs.sort_by{|a| a.val}.inject([]) do |uniqs, a|
  uniqs << a if uniqs.empty? || a.val != uniqs.last.val
  uniqs
end

Это для уникального 1 атрибута, но то же самое может быть сделано w/лексикографический вид...

0
ответ дан Purfideas 5 November 2019 в 08:48
поделиться

Мне нравится, когда использование jmah Хеша осуществляет уникальность. Вот пара большего количества способов освежевать ту кошку:

objs.inject({}) {|h,e| h[e.attr]=e; h}.values

Это - хороший 1 лайнер, но я подозреваю, что это могло бы быть немного быстрее:

h = {}
objs.each {|e| h[e.attr]=e}
h.values
5
ответ дан Head 5 November 2019 в 08:48
поделиться

Я первоначально предложил использовать select метод на Массиве. К остроумию:

[1, 2, 3, 4, 5, 6, 7].select{|e| e%2 == 0} дает нам [2,4,6] назад.

, Но если Вы хотите первое такой объект, используйте detect.

[1, 2, 3, 4, 5, 6, 7].detect{|e| e>3} дает нам 4.

я не уверен, для чего Вы идете сюда, все же.

6
ответ дан Alex M 5 November 2019 в 08:48
поделиться

Сделайте это на уровне базы данных:

YourModel.find(:all, :group => "status")
17
ответ дан mislav 5 November 2019 в 08:48
поделиться

Если я понимаю Ваш вопрос правильно, я занялся этой проблемой с помощью quasi-hacky подхода сравнения Упорядоченных объектов определить, варьируются ли какие-либо атрибуты. Введение в конце следующего кода было бы примером:

class Foo
  attr_accessor :foo, :bar, :baz

  def initialize(foo,bar,baz)
    @foo = foo
    @bar = bar
    @baz = baz
  end
end

objs = [Foo.new(1,2,3),Foo.new(1,2,3),Foo.new(2,3,4)]

# find objects that are uniq with respect to attributes
objs.inject([]) do |uniqs,obj|
  if uniqs.all? { |e| Marshal.dump(e) != Marshal.dump(obj) }
    uniqs << obj
  end
  uniqs
end
3
ответ дан Drew Olson 5 November 2019 в 08:48
поделиться

Добавьте uniq_by метод для Выстраивания в проекте. Это работает по аналогии с sort_by. Так uniq_by к uniq, как sort_by к sort. Использование:

uniq_array = my_array.uniq_by {|obj| obj.id}

реализация:

class Array
  def uniq_by(&blk)
    transforms = []
    self.select do |el|
      should_keep = !transforms.include?(t=blk[el])
      transforms << t
      should_keep
    end
  end
end

Примечание, что это возвращает новый массив вместо того, чтобы изменить Ваш текущий на месте. Мы не записали uniq_by! метод, но должно быть достаточно легко, если бы Вы хотели.

РЕДАКТИРОВАНИЕ: Tribalvibes указывает, что та реализация является O (n^2). Лучше было бы что-то как (непротестированный)...

class Array
  def uniq_by(&blk)
    transforms = {}
    select do |el|
      t = blk[el]
      should_keep = !transforms[t]
      transforms[t] = true
      should_keep
    end
  end
end
22
ответ дан Daniel Lucraft 5 November 2019 в 08:48
поделиться

Можно использовать хеш, который содержит только одно значение для каждого ключа:

Hash[*recs.map{|ar| [ar[attr],ar]}.flatten].values
2
ответ дан jmah 5 November 2019 в 08:48
поделиться
Другие вопросы по тегам:

Похожие вопросы: