2016-04-29 8 views
1

Ich habe Probleme beim Sortieren der folgenden Schlüsselwerte (Map). Berücksichtigen Sie, dass das Sortieren des Schlüssels wie erwartet mein Problem löst.So sortieren Sie hierarchische Schlüssel der Kartensammlung?

Erwarteter Ausgang

Key   Value 
1   animal 
1.1   dog 
1.1.1  tommy 
1.1.2  Lily 
1.1.10  Sadie 
1.2   cat 
1.3   camel 
1.3.2  camel2 
1.3.11  camel11 

Ich versuchte TreeMap aber es sortiert jedes Zeichen Nummer. was wird stattdessen dort verwendet, wenn es erforderlich ist, die ganze Zahl in String zu sortieren. Ich möchte etwas wie oben erwähnt in der erwarteten Ausgabe.

TreeMap<String, String> data = new TreeMap<String, String>();  
data.put("1", "animal"); 
data.put("1.1", "dog"); 
data.put("1.2", "cat");  
data.put("1.3", "camel"); 

data.put("1.3.2", "camel2"); 
data.put("1.3.11", "camel11"); 

data.put("1.1.1", "tommy"); 
data.put("1.1.2", "Lily"); 
data.put("1.1.10", "Sadie"); 


SortedSet<String> keys = new TreeSet<String>(data.keySet()); 

System.out.println("Key   Value"); 

for(String key: keys){ 
    System.out.println(key+"  "+data.get(key)); 

Tatsächliche Ausgabe

Key  Value 
1  animal 
1.1   dog 
1.1.1  tommy 
1.1.10  Sadie 
1.1.2  Lily 
1.2   cat 
1.3   camel 
1.3.11  camel11 
1.3.2  camel2 
+0

zu bekommen Dies aufgrund einer String Sortierung verursacht wird. 1.1.10 ist kleiner als 1.1.2. Vielleicht versuchen, die Zeichenfolge in Zahlen zu konvertieren und nur dann den Vergleich zu machen? Die erste Lösung, die mir in den Sinn kommt, ist, alle Punkte zu entfernen und dann nach Ganzzahl zu sortieren. So: 1110 wird größer als 112 und Ihre Ausgabe wird wie erwartet sein. – lazary

+0

Mögliches Duplikat von [Java: Einträge für Inhaltsverzeichnis sortieren] (http://stackoverflow.com/questions/29608890/java-sort-entries-for-table-of-contents) –

Antwort

4

Sie können eine benutzerdefinierte Comparator schreiben, die von den Perioden der Schlüsselfolge zusammenbricht und behandelt jedes Element als int:

public class VersionStringComparator implements Comparator<String> { 
    @Override 
    public int compare(String s1, String s2) { 
     String[] s1parts = s1.split("\\."); 
     String[] s2parts = s2.split("\\."); 
     int commonLength = Math.min(s1parts.length, s2parts.length); 

     // Loop and compare corresponding parts 
     for (int i = 0; i < commonLength; ++i) { 
      int partCompare = 
       Integer.compare(Integer.parseInt(s1parts[i]), 
           Integer.parseInt(s2parts[i])); 
      if (partCompare != 0) { 
       return partCompare; 
      } 
     } 

     // Out of parts - the shorter array should come first 
     return Integer.compare(s1parts.length, s2parts.length); 
    } 
} 

Diese Comparator kann dann in einem TreeMap verwendet werden:

TreeMap<String, String> data = new TreeMap<>(new VersionStringComparator()); 

Oder ein TreeSet:

TreeSet<String> keys = new TreeSet<>(new VersionStringComparator()); 

Beachten Sie, dass diese Implementierung VersionStringComparator davon ausgeht, dass sie nur auf Strings angewendet wird, die wie eine Folge von durch Punkte begrenzten Ganzzahlen aussehen. Wenn Sie dort andere Zeichenfolgen haben möchten, sollten Sie einige Eingabevalidierungen hinzufügen.

+0

Schön, upvoted. Ich habe eine tferer-Version zum Spaß gemacht: http://pastebin.com/4jAFDHQw – aioobe

+0

@aioobe netter Trick mit Rekursion dort. Nahm mich eine Minute, um zu verstehen, was du getan hast. Ich frage mich, ob es durch "Split" mehrere Male einen spürbaren Performance-Hit gibt. – Mureinik

1

Ich glaube, Sie einen Comparator zu Ihrem TreeMap Konstruktor übergeben wollen. Etwas wie:

class MyNumComp implements Comparator<String>{ 

    @Override 
    public int compare(String s1, String s2) { 

     // safely cast Strings to some int-type structure and compare 
     // return -1 if s1 < s2; return 0 if equal; else 1 

    } 
} 
3

Sie können den Code unten verwenden, um das Ergebnis Sie

erwartet
import java.util.Arrays; 
import java.util.Comparator; 
import java.util.Set; 
import java.util.TreeMap; 
import java.util.TreeSet; 

public class MapSort implements Comparator<String> { 

    @Override 
    public int compare(String v1, String v2) { 
     String[] a1 = v1.split("\\."); 
     String[] a2 = v2.split("\\."); 
     int min = 0; 
     int max = 0; 
     if (a1.length <= a2.length) { 
      min = a1.length; 
      max = a2.length; 
     } else { 
      min = a2.length; 
      max = a1.length; 
     } 
     int[] first = new int[max]; 
     int[] second = new int[max]; 
     for (int i = 0; i < a1.length; i++) { 
      first[i] = Integer.parseInt(a1[i]); 
     } 
     for (int i = 0; i < a2.length; i++) { 
      second[i] = Integer.parseInt(a2[i]); 
     } 

     for (int i = 0; i < min; i++) { 
      if (first[i] != second[i]) { 
       return first[i] > second[i] ? 1 : -1; 
      } 
     } 
     return 1; 
    } 

    public static void main(String[] args) { 

     TreeMap<String, String> data = new TreeMap<String, String>(); 
     data.put("1", "animal"); 
     data.put("1.1", "dog"); 
     data.put("1.2", "cat"); 
     data.put("1.3", "camel"); 

     data.put("1.3.2", "camel2"); 
     data.put("1.3.11", "camel11"); 

     data.put("1.1.1", "tommy"); 
     data.put("1.1.2", "Lily"); 
     data.put("1.1.10", "Sadie"); 

     Set<String> myset = new TreeSet<>(new MapSort()); 
     myset.addAll(data.keySet()); 

     for (String key : myset) { 
      System.out.println(key + ":" + data.get(key)); 
     } 
    } 

}