Ruby nach mehreren Werten sortieren?


78

Ich habe eine Reihe von Hashes:

a=[{ 'foo'=>0,'bar'=>1 },
   { 'foo'=>0,'bar'=>2 },
   ... ]

Ich möchte das Array zuerst nach dem 'foo' jedes Hashs und dann nach 'bar' sortieren. Google sagt mir, dass es so gemacht wird:

a.sort_by {|h| [ h['foo'],h['bar'] ]}

Dies gibt mir jedoch den ArgumentError "Vergleich von Array mit Array fehlgeschlagen". Was bedeutet das?


3
Funktioniert bei mir. Verwenden Sie eine alte Version von Ruby?
Alex Wayne

2
Was Sie gepostet haben, funktioniert in 1.8.7.
Phrogz

1
Ist es möglich, dass die Daten, die Sie zu haben glauben, und die Daten, die Sie tatsächlich haben, nicht identisch sind?
Wayne Conrad

24
Diese Ausnahme tritt auf, wenn das für den Vergleich verwendete Ergebnisarray sowohl Null- als auch Nicht-Null-Werte enthält.
Gucki

Beachten Sie auch, dass Ruby keine booleschen Werte vergleichen kann, was ebenfalls zu diesem Fehler führen kann.
Amöbe

Antworten:


83
a.sort { |a, b| [a['foo'], a['bar']] <=> [b['foo'], b['bar']] }

11
Das ist das gleiche. Enumerable#sort_by(&block)ist grob sort { |a,b| block.call(a) <=> block.call(b) }, außer auf effizientere Weise getan. Wenn dies funktioniert, sort_byaber nicht funktioniert, stimmt etwas anderes nicht.
Wuputah

Bei einfachen Schlüsseln ist die Sortierung effizienter. Bei komplexen Schlüsseln ist sort_by effizienter.
DJ2

1
Hmm, jetzt bekomme ich das "Du hast ein Null-Objekt, als du es nicht erwartet hast!" Error. Das genaue Array, das ich verwendet habe, ist a=[{'foo'=>0,'bar'=>2},{'foo'=>0,'bar'=>1},{'foo'=>2,'bar'=>1},{'foo'=>1,'bar'=>0}].
Herpderp

Funktioniert für mich. >> a = [{'foo' => 0, 'bar' => 2}, {'foo' => 0, 'bar' => 1}, {'foo' => 2, ' bar '=> 1}, {' foo '=> 1,' bar '=> 0}] => [{"foo" => 0, "bar" => 2}, {"foo" => 0, "bar" => 1}, {"foo" => 2, "bar" => 1}, {"foo" => 1, "bar" => 0}] >> a.sort {| a, b | [a ['foo'], a ['bar']] <=> [b ['foo'], b ['bar']]} => [{"foo" => 0, "bar" => 1}, {"foo" => 0, "bar" => 2}, {"foo" => 1, "bar" => 0}, {"foo" => 2, "bar" => 1} ]
DJ2

6
Ein Vorteil von sort_by ist, dass es trockener ist.
Andrew Grimm

24

Dies bedeutet wahrscheinlich, dass Sie eines der Felder "foo" oder "bar" in einem Ihrer Objekte vermissen.

Der Vergleich kommt nach unten , um so etwas wie nil <=> 2, die Renditen nil(anstelle von -1, 0oder 1) und #sort_byweiß nicht , wie zu handhaben nil.

Versuche dies:

a.sort_by {|h| [ h['foo'].to_i, h['bar'].to_i ]}

13

Was Sie gepostet haben, funktioniert in Ruby 1.8.7:

ruby-1.8.7-p302 > a = [{'foo'=>99,'bar'=>1},{'foo'=>0,'bar'=>2}]
 => [{"foo"=>99, "bar"=>1}, {"foo"=>0, "bar"=>2}] 

ruby-1.8.7-p302 > a.sort_by{ |h| [h['foo'],h['bar']] }
 => [{"foo"=>0, "bar"=>2}, {"foo"=>99, "bar"=>1}] 

ruby-1.8.7-p302 > a.sort_by{ |h| [h['bar'],h['foo']] }
 => [{"foo"=>99, "bar"=>1}, {"foo"=>0, "bar"=>2}] 

3

Diese Ausnahme tritt auf, wenn das für den Vergleich verwendete Ergebnisarray sowohl Null- als auch Nicht-Null-Werte enthält.


1

Dieser Fehler tritt auf, wenn Sie instabile Schlüssel haben und versuchen, nach diesen zu sortieren. Beispiel:

[{'foo'=>99,'bar'=>1},{'foo'=>0,'bar'=>2, 'qwe' => 7}]
a.sort_by{|v| v['qwe']}
ArgumentError: comparison of NilClass with 7 failed

Versuche es

a.sort_by{|v| [v['qwe']].select{|k| not k.nil?}}

Aber es funktioniert nicht für mich in

[v['index'],v['count'],v['digit'],v['value']]

wo die Ziffer instabil ist


1

Vergleich von Array mit Array fehlgeschlagen

Dies bedeutet (zumindest in meinem Fall), dass die Arten von Array-Elementen unterschiedlich sind. Als ich sicherstellte, dass alle Array-Elemente gleichzeitig sind ( Integerzum Beispiel), begann die Sortierung zu funktionieren.


0

Ziehen Sie in Betracht, das Array zu komprimieren (keine Einträge zu entfernen) und als Bonus, wenn es sich um einen Zeichenfolgenvergleich handelt, die Werte für die Sortierung ohne Berücksichtigung der Groß- und Kleinschreibung in Kleinbuchstaben zu schreiben.

a.compact.sort_by { |h| [h['foo'].downcase, h['bar'].downcase] }
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.