ruby-on-rails - array - ruby slice




Uniq nach Objektattribut in Ruby (9)

ActiveSupport-Implementierung:

def uniq_by
  hash, array = {}, []
  each { |i| hash[yield(i)] ||= (array << i) }
  array
end

Was ist die eleganteste Art, Objekte in einem Array auszuwählen, die in Bezug auf ein oder mehrere Attribute einzigartig sind?

Diese Objekte werden in ActiveRecord gespeichert, sodass die Verwendung der Methoden von AR auch in Ordnung wäre.


Der eleganteste Weg, den ich gefunden habe, ist ein Spin-off mit Array#uniq mit einem Block

enumerable_collection.uniq(&:property)

... es liest auch besser!


Ich hatte ursprünglich vorgeschlagen, die select Methode für Array zu verwenden. Nämlich:

[1, 2, 3, 4, 5, 6, 7].select{|e| e%2 == 0} [1, 2, 3, 4, 5, 6, 7].select{|e| e%2 == 0} gibt uns [2,4,6] zurück.

Wenn Sie jedoch das erste Objekt wünschen, verwenden Sie detect .

[1, 2, 3, 4, 5, 6, 7].detect{|e| e>3} [1, 2, 3, 4, 5, 6, 7].detect{|e| e>3} gibt uns 4 .

Ich bin mir aber nicht sicher, was Sie hier vorhaben.


Ich mag Jmahs Gebrauch eines Haschs, um Einzigartigkeit zu erzwingen. Hier sind ein paar weitere Möglichkeiten, diese Katze zu häuten:

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

Das ist ein schöner 1-Liner, aber ich vermute, das könnte ein bisschen schneller sein:

h = {}
objs.each {|e| h[e.attr]=e}
h.values


Sie können diesen Trick verwenden, um durch verschiedene Attribute Elemente aus dem Array eindeutig auszuwählen:

@photos = @photos.uniq { |p| [p.album_id, p.author_id] }

Tun Sie es auf der Datenbankebene:

YourModel.find(:all, :group => "status")

Wenn Sie nun nach den Attributwerten sortieren können, können Sie dies tun:

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

Das ist für ein 1-Attribut einzigartig, aber das gleiche kann mit lexikographischer Sortierung getan werden ...


Verwenden Sie Array#uniq mit einem Block:

@photos = @photos.uniq { |p| p.album_id }




unique