Yanıtlar:
Array#uniq
Bir blokla kullanın :
@photos = @photos.uniq { |p| p.album_id }
require 'backports'
@photos.uniq &:album_id
Ekle uniq_by
projenizde Array yöntemi. İle benzetme yaparak çalışır sort_by
. Yani uniq_by
etmektir uniq
olarak sort_by
etmektir sort
. Kullanımı:
uniq_array = my_array.uniq_by {|obj| obj.id}
Hayata geçirme:
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
Mevcut dizinizi yerinde değiştirmek yerine yeni bir dizi döndürdüğünü unutmayın. Henüz bir uniq_by!
yöntem yazmadık ama istersen yeterince kolay olmalı.
DÜZENLEME: Tribalvibes, uygulamanın O (n ^ 2) olduğuna işaret ediyor. Daha iyi bir şey (denenmemiş) ...
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
Bu numarayı, dizideki birkaç öznitelik elemanına göre benzersiz seçmek için kullanabilirsiniz:
@photos = @photos.uniq { |p| [p.album_id, p.author_id] }
Başlangıçta select
Array yöntemini kullanmayı önermiştim . Zekaya:
[1, 2, 3, 4, 5, 6, 7].select{|e| e%2 == 0}
bize [2,4,6]
geri verir .
Ancak böyle ilk nesneyi istiyorsanız, kullanın detect
.
[1, 2, 3, 4, 5, 6, 7].detect{|e| e>3}
bize verir 4
.
Yine de burada ne için gideceğinden emin değilim.
Sorunuzu doğru anlarsam, bu sorunu, herhangi bir özniteliğin farklılık gösterip göstermediğini belirlemek için Marshalled nesneleri karşılaştırmanın yarı-hacky yaklaşımını kullanarak çözdüm. Aşağıdaki kodun sonundaki enjekte bir örnek olacaktır:
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
Bulduğum en zarif yol Array#uniq
, bir blok ile kullanmaktır.
enumerable_collection.uniq(&:property)
… O da daha iyi okuyor!
Bir blokla Array # uniq kullanın :
objects.uniq {|obj| obj.attribute}
Veya daha özlü bir yaklaşım:
objects.uniq(&:attribute)
Rails'de ayrıca #uniq_by
yöntemi vardır.
Referans: Parametreli Dizi # uniq (yani, uniq_by)
Jmah ve Head'in cevaplarını seviyorum. Ama dizi sırasını koruyorlar mı? Ruby'nin sonraki sürümlerinde, dil spesifikasyonuna yazılan bazı hash ekleme-siparişi koruma gereksinimleri olduğu için bunlar olabilir, ancak burada, ne olursa olsun düzeni koruyan kullanmaktan hoşlandığım benzer bir çözüm var.
h = Set.new
objs.select{|el| h.add?(el.attr)}
Şimdi, öznitelik değerlerine göre sıralama yapabiliyorsanız, bu yapılabilir:
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
Bu, 1 özellikli benzersizdir, ancak aynı şey sözlükbilimsel sıralama ile de yapılabilir ...