2017-08-08 5 views
0

Ich habe einfach eine einfache Vergleichsmethode, um eine Map nach der Größe des Wertes zu sortieren, der eine Menge ist.Karte nach Wert sortieren

public List<Entry<String, HashSet<String>>> orderByDescStringSetSize(HashMap<String, HashSet<String>> map){ 
    Set<Entry<String, HashSet<String>>> set = map.entrySet(); 
    List<Entry<String, HashSet<String>>> list = new ArrayList<Entry<String, HashSet<String>>>(set); 

    Collections.sort(list, new Comparator<Map.Entry<String, HashSet<String>>>(){ 
     public int compare(Map.Entry<String, HashSet<String>> o1, Map.Entry<String, HashSet<String>> o2){ 

      Integer o1Vals = o1.getValue().size(); 
      Integer o2Vals = o2.getValue().size(); 

      //descending 
      if(o2Vals > o1Vals) 
       return 1; 
      else if(o2Vals==o1Vals) 
       return 0; 
      else 
       return -1; 

     } 
    }); 
    return list; 
} 

Ich bekomme java.lang.IllegalArgumentException: Comparison method violates its general contract! Warum?

+3

Mögliches Duplikat von ["Vergleichsmethode verletzt seinen allgemeinen Vertrag!"] (Https://stackoverflow.com/questions/8327514/comparison-method-violates-its-general-contract) – Guy

+0

Fügen Sie ein Beispiel hinzu der Map, die zum Auslösen der Ausnahme führt. – Oleg

+0

Ja bei der Duplizierung. Ich würde vorschlagen, "o2Vals - o1Vals;" zurückzubringen, und es sollte Ihnen gut gehen. – daniu

Antwort

2

Es ist, weil nicht tut, was Sie erwarten.

Sie arbeiten mit IntegerObjekte - bitte verwenden Sie equals !!

Dies ist möglicherweise nicht das einzige Problem.

+0

Vielen Dank !! Ich habe nicht darüber nachgedacht – Song

+1

Oder besser, verwenden Sie 'int' hier, da es keinen Grund gibt,' Integer' zu verwenden, wenn 'size()' ein 'int' zurückgibt. Oder vereinfachen Sie die gesamte Methode zum Zurückgeben von Integer.compare (o1.getValue(). Size(), o2.getValue(). Size()); – Holger

0

mit dem gleichen Ansatz, den Sie ich ändern tat wird:

  • Die Größe des HashSets ein int ist es eher für den Vergleich zu verwenden als Integer.
  • Keine Notwendigkeit, if else if else hinzuzufügen, wenn Sie den Wert zurückgeben. Außerdem können Sie nur die subtrahierten Werte zurückgeben: return o2Vals - o1Vals.
  • Sie verwenden Entry in einigen Punkten und Map.Entry, sind Sie sicher, dass Sie die richtigen Importe haben? In jedem Fall empfehle ich Ihnen, immer das eine oder das andere zu verwenden, um sicherzustellen, dass die Typen gleich sind.

Dieser sagte, sollte die Lösung wie folgt aussehen:

public List<Entry<String, HashSet<String>>> orderByDescStringSetSize2(HashMap<String, HashSet<String>> map) { 
    Set<Entry<String, HashSet<String>>> set = map.entrySet(); 
    List<Entry<String, HashSet<String>>> list = new ArrayList<>(set); 

    Collections.sort(list, new Comparator<Entry<String, HashSet<String>>>() { 

    @Override 
    public int compare(Entry<String, HashSet<String>> o1, Entry<String, HashSet<String>> o2) { 
     int o1Vals = o1.getValue().size(); 
     int o2Vals = o2.getValue().size(); 

     // Descending 
     return o2Vals - o1Vals; 
    } 
    }); 
    return list; 
} 

jedoch, wenn Sie mit Java 8 Sie die Vorteile der Stream Schnittstelle nehmen und tun es kompakter ohne Definition eines Comparator:

public List<Entry<String, HashSet<String>>> orderByDescStringSetSize(HashMap<String, HashSet<String>> map) { 
    return map.entrySet().stream() // Create stream 
      .sorted(Comparator.comparing(entry -> -((Entry<String, HashSet<String>>) entry).getValue().size())) // Sort descending 
      .collect(Collectors.toList()); // Collect 
}