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?

ich Idiot
quelle
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']] }
dj2
quelle
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 ]}
Will Madden
quelle
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}] 
Phrogz
quelle
3

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

Weston Ganger
quelle
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

user3713526
quelle
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.

yegor256
quelle
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] }
VinnyQ77
quelle