जवाबों:
Array#uniq
एक ब्लॉक के साथ प्रयोग करें :
@photos = @photos.uniq { |p| p.album_id }
require 'backports'
@photos.uniq &:album_id
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!
विधि नहीं लिखी है लेकिन यदि आप चाहते हैं तो यह काफी आसान होना चाहिए।
EDIT: ट्राइबलविब्स बताते हैं कि कार्यान्वयन 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
आप सरणी से कई विशेषताओं तत्वों द्वारा अद्वितीय का चयन करने के लिए इस चाल का उपयोग कर सकते हैं:
@photos = @photos.uniq { |p| [p.album_id, p.author_id] }
मैंने मूल रूप से 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
।
मुझे यकीन नहीं है कि आप यहाँ क्या कर रहे हैं, हालांकि।
मैं विशिष्टता को लागू करने के लिए एक हैश के जेएमए के उपयोग को पसंद करता हूं। यहाँ एक और तरीका है कि बिल्ली को त्वचा के लिए कुछ और तरीके:
objs.inject({}) {|h,e| h[e.attr]=e; h}.values
यह एक अच्छा 1-लाइनर है, लेकिन मुझे संदेह है कि यह थोड़ा तेज हो सकता है:
h = {}
objs.each {|e| h[e.attr]=e}
h.values
यदि मैं आपके प्रश्न को सही ढंग से समझता हूं, तो मैंने मार्श किए गए ऑब्जेक्ट्स की तुलना करने के क्वैसी-हैकी दृष्टिकोण का उपयोग करके इस समस्या से निपटा है, यह निर्धारित करने के लिए कि क्या कोई विशेषता भिन्न है। निम्नलिखित कोड के अंत में इंजेक्शन एक उदाहरण होगा:
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
सबसे सुंदर तरीका जो मैंने पाया है वह Array#uniq
एक ब्लॉक के साथ स्पिन-ऑफ का उपयोग करना है
enumerable_collection.uniq(&:property)
... यह बेहतर भी पढ़ता है!
एक ब्लॉक के साथ Array # uniq का उपयोग करें :
objects.uniq {|obj| obj.attribute}
या अधिक संक्षिप्त दृष्टिकोण:
objects.uniq(&:attribute)
रेलों की भी एक #uniq_by
विधि होती है।
मुझे जेमाह और हेड के जवाब पसंद हैं। लेकिन क्या वे सरणी ऑर्डर को संरक्षित करते हैं? वे रूबी के बाद के संस्करणों में हो सकते हैं क्योंकि भाषा विनिर्देश में कुछ हैश प्रविष्टि-आदेश-संरक्षण आवश्यकताओं को लिखा गया है, लेकिन यहां एक समान समाधान है जो मुझे उपयोग करना पसंद है जो कि आदेश की परवाह किए बिना संरक्षित करता है।
h = Set.new
objs.select{|el| h.add?(el.attr)}
अब यदि आप विशेषता मानों को क्रमबद्ध कर सकते हैं तो यह किया जा सकता है:
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 / lexicographic तरह किया जा सकता है ...