2012-12-20 8 views
12

Ich habe Problem mit Standard Komparator für Strings (in SortedSet). Das Problem ist, dass Standard-Komparator sortiert nicht gut String, enthält Zahlen, dh: In Satz i haben:Sortierung Strings, die Zahl in Java enthält

room1, room2, room100 

Natürliche Ordnung wie oben, aber in Reihe sein sollte, ich habe:

room1, room100, room2 

I Ich weiß, warum es so ist, aber ich weiß nicht, wie ich es ändern soll.

+6

Sie benötigen eine benutzerdefinierte comparartor erstellen –

+0

Ich weiß, aber ich habe keine Ahnung, wie es zu vergleichen. Wissen, ich versuche mit diesem: > private int compareNumbers (Zeichenfolge o1, String o2) { Muster numberPattern = Pattern.compile (PATTERN); Matcher matcher1 = NummerPattern.Matcher (o1); Matcher matcher2 = NummerPattern.Matcher (o2); int i1 = Ganzzahl.parseInt (matcher1.group()); int i2 = Ganzzahl.parseInt (matcher2.group()); System.out.println (i1 + "" + i2); Rückgabe i1 - i2; } – MAGx2

+0

Sie müssen Annahmen treffen, wie zum Beispiel, alle Zeichenfolge im Format ? oder entscheiden Sie, was genau Ihr Format ist, nur dann können Sie Ihren Komparator schreiben –

Antwort

22

Versuchen Sie, diese Komparator (Strings aus beliebigen Zeichen beginnen), die alle nicht stelligen entfernt Zeichen vergleicht dann die übrigen Zeichen als Nummern:

Collections.sort(strings, new Comparator<String>() { 
    public int compare(String o1, String o2) { 
     return extractInt(o1) - extractInt(o2); 
    } 

    int extractInt(String s) { 
     String num = s.replaceAll("\\D", ""); 
     // return 0 if no digits found 
     return num.isEmpty() ? 0 : Integer.parseInt(num); 
    } 
}); 

Hier ist ein Test:

public static void main(String[] args) throws IOException { 
    List<String> strings = Arrays.asList("room1", "foo", "room2", "room100", "room10"); 
    Collections.sort(strings, new Comparator<String>() { 
     public int compare(String o1, String o2) { 
      return extractInt(o1) - extractInt(o2); 
     } 

     int extractInt(String s) { 
      String num = s.replaceAll("\\D", ""); 
      // return 0 if no digits found 
      return num.isEmpty() ? 0 : Integer.parseInt(num); 
     } 
    }); 
    System.out.println(strings); 
} 

Ausgang:

[foo, room1, room2, room10, room100] 
+0

Danke :). Es funktioniert. Die einzige Sache, die ich ändern werde, ist, wenn einer der Schnur ohne Zahlen normal ist :). – MAGx2

+0

Ich habe Code hinzugefügt, der sich mit "keine Zahlen" für Sie beschäftigt – Bohemian

+0

Warum, wenn ich Ihren Algorithmus mit List strings ausführen = Arrays.asList ("a", "aaa"); Das Ergebnis ist anders als Liste strings = Arrays.asList ("aaa", "a"); ? Ich glaube, das Ergebnis sollte das gleiche sein. Bitte sagen Sie mir, wenn ich einen Fehler habe ... – Goose

0

Sie können einen Komparator implementieren und an den Satz Konstruktor übergeben. Siehe http://docs.oracle.com/javase/1.4.2/docs/api/java/util/Comparator.html.

Wenn alle Ihre Strings in Form von Raum [Zahl] sind, können Sie den „Raum“ abzustreifen die Zahl analysieren und sie vergleichen.
Alternativ - Sie können Ganzzahlen in Sie speichern und drucken Sie sie mit "Raum" Präfix.

+0

Aber ich habe keine Idee, wie man es vergleicht. Einige Regex? – MAGx2

+1

Sind die Strings immer in Form von Raum [Nummer]? –

5

versuchen Sie dies. Ich habe angenommen, dass du immer "Raum" am Anfang deiner Schnur haben wirst.

List<String> list = Arrays.asList("room1", "room100", "room2"); 
    Collections.sort(list, new Comparator<String>() 
    { 
     @Override 
     public int compare(String o1, String o2) 
     { 
      return new Integer(o1.replaceAll("room", "")) 
       .compareTo(new Integer(o2.replaceAll("room", ""))); 
     } 

    }); 
+0

@Vikdor danke für die Bearbeitung – RNJ

2

Hier ist meine Comparator Implementierung für eine solche Art:

public class StringNumberComparator implements Comparator<String>{ 

    @Override 
    public int compare(String o1, String o2) { 
    int i1 = this.getRearInt(o1); 
    int i2 = getLeadingInt(o2); 
    String s1 = getTrailingString(o1); 
    String s2 = getTrailingString(o2); 

    if(i1==i2) 
     return s1.compareTo(s2); 
    if(i1>i2) 
     return 1; 
    else if(i1<i2) 
      return -1; 
    return 0; 
    } 

    private int getRearInt(String s) { 
    s=s.trim(); 
    int i=Integer.MAX_VALUE; 
    try { 
      i = Integer.parseInt(s.split("[^0-9]+")[1]); 
    } catch(ArrayIndexOutOfBoundsException e) { 

    } catch(NumberFormatException f) { 
      return i; 
    } 

    return i; 
    } 

    private String getTrailingString(String s) { 

    return s.replaceFirst("[0-9]", ""); 

} }

0

Eine faule Alternative wäre, die Folgenkomparators Arbeit zu machen, ohne zusätzlich etwas zu tun (Ihr eigenes Komparator definiert wird). Sie können dies durch Auffüllen mit Nullen die Zahlen in Ihrem String wie folgt haben: room0001, room0002, room0100 dann funktioniert der Standard-String-Vergleicher. Sie müssen jedoch den maximalen Zahlenwert kennen, damit Sie Ihr Padding entsprechend anpassen können.

4

Gebrauchte @bohemian Antwort. Nur ein bisschen verbessert. Das funktionierte sehr gut für mich ..

 Collections.sort(asdf, new Comparator<String>() { 
      public int compare(String o1, String o2) { 

       String o1StringPart = o1.replaceAll("\\d", ""); 
       String o2StringPart = o2.replaceAll("\\d", ""); 


       if(o1StringPart.equalsIgnoreCase(o2StringPart)) 
       { 
        return extractInt(o1) - extractInt(o2); 
       } 
       return o1.compareTo(o2); 
      } 

      int extractInt(String s) { 
       String num = s.replaceAll("\\D", ""); 
       // return 0 if no digits found 
       return num.isEmpty() ? 0 : Integer.parseInt(num); 
      } 
     }); 
Verwandte Themen