Odpowiedzi:
Używaj Array#uniq
z blokiem:
@photos = @photos.uniq { |p| p.album_id }
require 'backports'
:-)
@photos.uniq &:album_id
Dodaj uniq_by
metodę do Array w swoim projekcie. Działa przez analogię z sort_by
. Tak uniq_by
jest, uniq
jak sort_by
jest sort
. Stosowanie:
uniq_array = my_array.uniq_by {|obj| obj.id}
Implementacja:
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
Zwróć uwagę, że zwraca on nową tablicę, zamiast modyfikować bieżącą w miejscu. Nie napisaliśmy uniq_by!
metody, ale powinna być dość łatwa, jeśli chcesz.
EDYCJA: Tribalvibes zwraca uwagę, że ta implementacja to O (n ^ 2). Lepiej byłoby coś takiego (niesprawdzone) ...
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
Zrób to na poziomie bazy danych:
YourModel.find(:all, :group => "status")
Możesz użyć tej sztuczki, aby wybrać unikalne przez kilka atrybutów elementów z tablicy:
@photos = @photos.uniq { |p| [p.album_id, p.author_id] }
Jeśli dobrze rozumiem twoje pytanie, rozwiązałem ten problem, stosując quasi-hackowe podejście do porównywania obiektów Marshaled w celu ustalenia, czy jakiekolwiek atrybuty się różnią. Przykładem może być wstrzyknięcie na końcu następującego kodu:
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
Najbardziej elegancki sposób, jaki znalazłem, to spin-off Array#uniq
z blokiem
enumerable_collection.uniq(&:property)
… Też czyta się lepiej!
Użyj Array # uniq z blokiem:
objects.uniq {|obj| obj.attribute}
Lub bardziej zwięzłe podejście:
objects.uniq(&:attribute)
Railsy mają również #uniq_by
metodę.
Odniesienie: sparametryzowana tablica # uniq (tj. Uniq_by)
Lubię odpowiedzi jmah i Head. Ale czy zachowują porządek w tablicy? Mogą być w późniejszych wersjach ruby, ponieważ w specyfikacji języka zostały zapisane pewne wymagania dotyczące zachowania kolejności wstawiania skrótów, ale tutaj jest podobne rozwiązanie, którego lubię używać, które zachowuje porządek niezależnie.
h = Set.new
objs.select{|el| h.add?(el.attr)}
Teraz, jeśli możesz sortować według wartości atrybutów, możesz to zrobić:
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
To dla unikatowego atrybutu 1, ale to samo można zrobić z sortowaniem leksykograficznym ...