2017-01-01 4 views
2

Ich habe ein Array wenn IDs aus einer Tabelle, zum Beispiel:sortieren Liste von Objekten gemäß einem Array (Rails)

b = [659, 658, 656, 645, 644, 657, 634, 643, 649, 650, 651, 636, 633, 607, 605, 604, 648, 647, 675, 674, 667, 499] 

ich es verwenden, um eine Liste von Objekten von TAT Tabelle Abrufen:

k = Photo.where(id:b) 

Was ich bekomme, ist eine Liste von Objekten, die nicht in der gleichen Reihenfolge wie das Array sortiert sind.

Wie kann ich das tun?

+0

Es sieht aus wie Ihre Antwort kann hier sein: http://stackoverflow.com/questions/11961685/sort-an-array-according-to-the-elements-of-another-array – jvillian

+0

@jvillian Dank - Sie befinden sich Recht. Es gibt mehrere Vorschläge im Thread. Ich bin nicht mit der Antwort gegangen. Stattdessen ging ich mit dieser http://stackoverflow.com/a/25297497/3508526 – martin

Antwort

2

Wenn IDs sind eindeutig

können Sie verwenden index_by und values_at:

k = Photo.where(id: b).index_by(&:id).values_at(*b) 

Beispiel:

b = [5,3,1] 
Country.where(id: b) 
#=> [#<Country id: 1, name: "France">, #<Country id: 3, name: "Ukraine">, #<Country id: 5, name: "Spain">] 
Country.where(id: b).index_by(&:id) 
#=> {1=>#<Country id: 1, name: "France">, 3=>#<Country id: 3, name: "Ukraine">, 5=>#<Country id: 5, name: "Spain">} 
Country.where(id: b).index_by(&:id).values_at(*b) 
#=> [#<Country id: 5, name: "Spain">, #<Country id: 3, name: "Ukraine">, #<Country id: 1, name: "France">] 

Wenn b doppelte Ids

Mit b = [5,3,3,1] enthält, die erste Methode würde ausgeben:

#=> [#<Country id: 5, name: "Spain">, #<Country id: 3, name: "Ukraine">, #<Country id: 3, name: "Ukraine">, #<Country id: 1, name: "France">] 

können Sie verwenden index_by und slice:

k = Photo.where(id: b).index_by(&:id).slice(*b).values 

mit:

b = [5,3,3,1] 
Country.where(id: b) 
#=> [#<Country id: 1, name: "France">, #<Country id: 3, name: "Ukraine">, #<Country id: 5, name: "Spain">] 
Country.where(id: b).index_by(&:id) 
#=> {1=>#<Country id: 1, name: "France">, 3=>#<Country id: 3, name: "Ukraine">, 5=>#<Country id: 5, name: "Spain">} 
Country.where(id: b).index_by(&:id).slice(*b) 
#=> {5=>#<Country id: 5, name: "Spain">, 3=>#<Country id: 3, name: "Ukraine">, 1=>#<Country id: 1, name: "France">} 
Country.where(id: b).index_by(&:id).slice(*b).values 
#=> [#<Country id: 5, name: "Spain">, #<Country id: 3, name: "Ukraine">, #<Country id: 1, name: "France">] 

Natürlich könnten Sie auch mit b.uniq

1

Eine Active Abfrage die erste Methode verwenden, wie Photo.where(id: some_array) erzeugt SQL wie folgt:

select ... from photos where id in (...) 

aber die Reihenfolge der Elemente in der IN hat keine Beziehung zu dem, was die Datenbank-Bestellung in den Zeilen zurückgibt; Im Allgemeinen bestimmt nur die ORDER BY-Klausel die Reihenfolge der Zeilen.

Sie die Datenbank erhalten können Dinge bestellen Sie Ihre b Array mit einem Fall entsprechen:

order by case id when 659 then 0 when 658 then 1 ... end 

und das ist ziemlich leicht in Ruby zu konstruieren:

Photo.where(id: b) 
    .order(%Q{case id #{b.map.each_with_index { |id, i| "when #{id} then #{i}" }.join(' ')} end }) 

Nicht besonders hübsch Ich nehme an, aber es bringt die Datenbank dazu, die Arbeit zu erledigen (was wichtig sein könnte, wenn Sie mehr Dinge in diese Abfrage verketten) und Sie können die Hässlichkeit innerhalb einer Klassenmethode auf Foto:

leicht verbergen
def self.for_ids_in_order(ids) 
    where(id: ids).order(%Q{case id #{ids.map.each_with_index { |id, i| "when #{id} then #{i}" }.join(' ')} end }) 
end 

und dann sagen Photo.for_ids_in_order(b).

Natürlich geht das davon aus, dass Sie wissen, woher das b Array stammt und dass Sie wissen, dass es Ganzzahlen enthält.Wenn Sie nicht sicher sind, davon können Sie einen Anruf connection.quote einwerfen, dass die Dinge zu machen, richtig übersetzt werden:

ids.map.each_with_index { |id, i| "when #{connection.quote(id)} then #{i}" }... 
0

b.map {| m | Photo.find (m)} wenn die IDs im b-Array eindeutig sind. Wenn nicht dann führen Sie diese b.uniq.map {| m | Photo.find (m)} Ein Nachteil dieses Codes besteht darin, dass er eine Abfrage für alle im b-Array vorhandenen Elemente ausführt.

Verwandte Themen