2016-08-18 2 views
0

für das folgende Array:Rubin alphanumerische Sortierung nicht wie erwartet funktioniert

y = %w[A1 A2 B5 B12 A6 A8 B10 B3 B4 B8] 
=> ["A1", "A2", "B5", "B12", "A6", "A8", "B10", "B3", "B4", "B8"] 

Mit der erwarteten sortiert Array zu sein:

=> ["A1", "A2", "A6", "A8", "B3", "B4", "B5", "B8", "B10", "B12"] 

Unter Verwendung der folgenden (Vanille) Art, die ich erhalten:

irb(main):2557:0> y.sort{|a,b| puts "%s <=> %s = %s\n" % [a, b, a <=> b]; a <=> b} 
A1 <=> A8 = -1 
A8 <=> B8 = -1 
A2 <=> A8 = -1 
B5 <=> A8 = 1 
B4 <=> A8 = 1 
B3 <=> A8 = 1 
B10 <=> A8 = 1 
B12 <=> A8 = 1 
A6 <=> A8 = -1 
A1 <=> A2 = -1 
A2 <=> A6 = -1 
B12 <=> B3 = -1 
B3 <=> B8 = -1 
B5 <=> B3 = 1 
B4 <=> B3 = 1 
B10 <=> B3 = -1 # this appears to be wrong, looks like 1 is being compared, not 10. 
B12 <=> B10 = 1 
B5 <=> B4 = 1 
B4 <=> B8 = -1 
B5 <=> B8 = -1 
=> ["A1", "A2", "A6", "A8", "B10", "B12", "B3", "B4", "B5", "B8"] 

... was offensichtlich nicht das ist, was ich begehre. Ich weiß, dass ich versuchen kann, zuerst auf Alpha zu splitten und dann die Zahlen zu sortieren, aber es scheint so, als müsste ich das nicht tun.

Mögliche großer Nachteil: wir Rubin stecken mit 1.8.7 für jetzt :(Aber auch Ruby-2.0.0 ist das Gleiche zu tun, was ich hier fehlt

Vorschläge

+3

Ihre erste Ahnung ist die richtige; Da dies Strings sind, werden sie lexikografisch geordnet. Wenn Sie die Nummer als Element der Bestellung berücksichtigen möchten, müssen Sie den Buchstaben von der Nummer trennen und beim Sortieren nach eigenem Ermessen verwenden. – Makoto

+2

Ich bin gespannt, warum Sie denken, die * Zeichenfolge * "B12" würde vor der * Zeichenfolge * "B2" sortiert werden. So sortiert Ruby keine Strings, so sortiert * everything * Strings. – meagar

+0

Sie möchten 'y.sort_by {| s | [s [0], s [1 ..- 1] .to_i]} # => ["A1", "A2", "A6", "A8", "B3", "B4", "B5", "B8", "B10", "B12"] '. In [Array # <=>] (http://ruby-doc.org/core-2.3.0/Array.html#method-i-3C-3D-3E) finden Sie Informationen dazu, wie Ruby Arrays sortiert. –

Antwort

1

Sie sortieren Strings. Strings werden wie Strings sortiert, nicht wie Zahlen. Wenn Sie nach Zahlen sortieren möchten, sollten Sie Zahlen und keine Zeichenfolgen sortieren. Die Zeichenkette 'B10' ist lexikografisch kleiner als die Zeichenkette 'B3', das ist nicht etwas, was Ruby einzigartig ist, das ist nicht einmal etwas Einzigartiges in der Programmierung, so dass ein Textstück lexikographisch so ziemlich überall in Programmen, Datenbanken, Lexika, Wörterbüchern, Telefonbüchern funktioniert. usw.

Sie sollten Ihre Strings in ihre numerischen und nicht numerischen Komponenten aufteilen und die numerischen Komponenten in Zahlen umwandeln. Array-Sortierung ist lexikographisch, so dass dies am Ende genau richtig sortiert:

y.sort_by {|s| # use `sort_by` for a keyed sort, not `sort` 
    s. 
    split(/(\d+)/). # split numeric parts from non-numeric 
    map {|s| # the below parses numeric parts as decimals, ignores the rest 
     begin Integer(s, 10); rescue ArgumentError; s end }} 
#=> ["A1", "A2", "A6", "A8", "B3", "B4", "B5", "B8", "B10", "B12"] 
-1

A.? natürliches oder lexikographisches Sortieren, kein Standardzeichenwertbasierten Sortieren, benötigt wäre so etwas wie dieses gems ein Ausgangspunkt sein würde. https://github.com/dogweather/naturally,

Humans eine Zeichenkette wie „A2“, wie „A“ behandelt, gefolgt https://github.com/johnnyshields/naturalsort durch die Nummer 2, und sortieren Sie mit Zeichenfolge Sortierung für den String-Teil und numerische Sortierung für die numerische pa rt. Standard sort() verwendet Zeichen-Wert-Sortierung, die die Zeichenfolge als eine Folge von Zeichen behandelt, unabhängig davon, was die Zeichen sind. Also für sort() "A10" und "A2" aussehen wie ['A', '1', '0'] und ['A', '2'], da '1' vor '2' sortiert und die folgenden Zeichen können ändere diese Reihenfolge nicht "A10" sortiert also vor "A2". Für Menschen sehen die gleichen Strings wie ["A", 10] und ["A", 2], 10 Arten nach 2 aus, so dass wir das gegenteilige Ergebnis erhalten. Die Zeichenfolgen können so manipuliert werden, dass das Zeichenwert-basierte sort() das erwartete Ergebnis erzeugt, indem der numerische Teil mit fester Breite und Null-Padding links gemacht wird, um eingebettete Leerzeichen zu vermeiden, wodurch "A2" zu "A02" wird Sortierung vor "A10" mit Standard sort().

+0

Das löst zwar das Problem, aber es erklärt nicht, warum die Sortierung nicht sofort funktioniert. Sehr interessant, obwohl. – Jim

+1

Numerische Werte werden anders sortiert als die Sortierung ihrer Zeichenfolgen nach Zeichen. Eine Zeichenwert-Sortierung funktioniert z. B. nicht. "A10" und "A2", weil der Zeichenwert für "1" kleiner als für "2" ist und das "A10" vor "A2" sortiert. Eine natürliche Art, OTOH, würde "A2" als äquivalent zu "A02" oder ["A", 2] interpretieren (so wie wir es behandeln würden, als "A" gefolgt von der Nummer 2). –

+1

NB: das oben ist der Grund, warum Sie Zahlen in Zahlenfeldern mit fester Breite und fester Dezimalstelle so oft in Datendateien rechtsbündig sehen, dass die Sortierung der Zeichen den Ergebnissen einer numerischen Sortierung entspricht. –

Verwandte Themen