144 Stimmen

Uniq nach Objekt-Attribut in Ruby

Wie lassen sich Objekte in einem Array, die in Bezug auf ein oder mehrere Attribute eindeutig sind, am elegantesten heraussuchen?

Diese Objekte sind in ActiveRecord gespeichert, so dass die Verwendung von AR-Methoden auch in Ordnung wäre.

229voto

Lane Punkte 4052

Utilisez Array#uniq mit einem Block:

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

5 Stimmen

Dies ist die richtige Antwort für Rubin 1.9 und spätere Versionen.

3 Stimmen

+1. Und für frühere Rubine gibt es immer require 'backports' :-)

0 Stimmen

Die Hash-Methode ist besser, wenn Sie nach z. B. album_id gruppieren und dabei (z. B.) num_plays aufsummieren möchten.

22voto

Daniel Lucraft Punkte 6926

Fügen Sie die uniq_by Methode zu Array in Ihrem Projekt. Es funktioniert analog zu sort_by . Also uniq_by soll uniq als sort_by soll sort . Verwendung:

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

Die Umsetzung:

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

Beachten Sie, dass ein neues Array zurückgegeben wird, anstatt das aktuelle Array zu ändern. Wir haben nicht geschrieben ein uniq_by! Methode, aber es sollte einfach genug sein, wenn Sie es wollen.

EDIT: Tribalvibes weist darauf hin, dass diese Implementierung O(n^2) ist. Besser wäre etwas wie (ungetestet)...

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

1 Stimmen

Nizza api, aber das wird schlecht (sieht aus wie O(n^2)) Skalierung Leistung für große Arrays haben. Könnte behoben werden, indem man Transformationen ein Hashset.

7 Stimmen

Diese Antwort ist nicht mehr aktuell. Ruby >= 1.9 hat Array#uniq mit einem Block, der genau dies tut, wie in der akzeptierten Antwort.

17voto

mislav Punkte 14351

Tun Sie es auf der Ebene der Datenbank:

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

1 Stimmen

Und was wäre, wenn es sich um mehr als ein Feld handeln würde, nur aus Interesse?

17voto

yauhenininjia Punkte 188

Sie können diesen Trick verwenden, um eindeutige Elemente mit mehreren Attributen aus einem Array auszuwählen:

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

0 Stimmen

So offensichtlich, so Ruby. Ein weiterer Grund, Ruby zu segnen

6voto

Alex M Punkte 2438

Ich hatte ursprünglich vorgeschlagen, die select Methode auf Array. Und zwar:

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

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

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

Ich bin mir allerdings nicht sicher, worauf Sie hier hinauswollen.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X