Ich möchte einen Komparator schreiben, mit dem ich eine TreeMap anstelle der natürlichen Standardreihenfolge nach Wert sortieren kann.
Ich habe so etwas versucht, kann aber nicht herausfinden, was schief gelaufen ist:
import java.util.*;
class treeMap {
public static void main(String[] args) {
System.out.println("the main");
byValue cmp = new byValue();
Map<String, Integer> map = new TreeMap<String, Integer>(cmp);
map.put("de",10);
map.put("ab", 20);
map.put("a",5);
for (Map.Entry<String,Integer> pair: map.entrySet()) {
System.out.println(pair.getKey()+":"+pair.getValue());
}
}
}
class byValue implements Comparator<Map.Entry<String,Integer>> {
public int compare(Map.Entry<String,Integer> e1, Map.Entry<String,Integer> e2) {
if (e1.getValue() < e2.getValue()){
return 1;
} else if (e1.getValue() == e2.getValue()) {
return 0;
} else {
return -1;
}
}
}
Ich denke, was ich frage ist: Kann ich eine Map.Entry
Übergabe an den Komparator bekommen?
Antworten:
Sie können
TreeMap
die Werte nicht selbst sortieren lassen, da dies derSortedMap
Spezifikation widerspricht :Mit einer externen Sammlung können Sie jedoch jederzeit
Map.entrySet()
nach Schlüsseln, Werten oder sogar einer Kombination (!!) der beiden sortieren, wie Sie möchten.Hier ist eine generische Methode, die a
SortedSet
von zurückgibtMap.Entry
, vorausgesetzt,Map
deren Werte sindComparable
:Jetzt können Sie Folgendes tun:
Beachten Sie, dass funky Dinge passieren, wenn Sie versuchen, entweder das
SortedSet
Selbst oder das Innere zu ändernMap.Entry
, da dies keine "Ansicht" der ursprünglichen Karte mehr ist, wie sieentrySet()
ist.Im Allgemeinen ist die Notwendigkeit, die Einträge einer Karte nach ihren Werten zu sortieren, untypisch.
Hinweis
==
fürInteger
Ihr ursprünglicher Komparator vergleicht
Integer
mit==
. Dies ist fast immer falsch, da es sich==
beiInteger
Operanden um eine Referenzgleichheit handelt, nicht um eine Wertgleichheit.Verwandte Fragen
new Integer(i) == i
in Java garantiert ? (JA!!!)quelle
Die Antwort auf Polygenschmierstoffe ist nahezu perfekt. Es hat jedoch einen wichtigen Fehler. Karteneinträge mit gleichen Werten werden nicht verarbeitet.
Dieser Code: ...
Würde ausgeben:
Beachten Sie, wie unsere Kuh verschwand, als sie den Wert "1" mit unserem Affen teilte: O!
Diese Änderung des Codes löst dieses Problem:
quelle
Set
Implementierung enthält ein Element mehr als einmal. Sie haben gerade diese Einschränkung verletzt. Über dieSortedSet
API: Beachten Sie, dass die Reihenfolge, die von einem sortierten Satz verwaltet wird , mit gleich .... übereinstimmen muss . Die Lösung wäre, zu einerList
Implementierung zu wechseln .Set
s. Da dasComparator
gegen denSet
Vertrag verstößtSet.remove
, funktioniertSet.contains
etc nicht ! Überprüfen Sie dieses Beispiel bei ideone .int res= e1.getValue().compareTo(e2.getValue());
inint res= e2.getValue().compareTo(e1.getValue());
, haben Sie eine absteigende Werte statt aufsteigend sortiert.res != 0 ? res : e1.getKey().compareTo(e2.getKey())
, um die Reihenfolge der Schlüssel mit gleichen Werten beizubehalten.In Java 8:
quelle
A
TreeMap
wird immer nach den Schlüsseln sortiert, alles andere ist unmöglich. Mit AComparator
können Sie lediglich steuern, wie die Schlüssel sortiert werden.Wenn Sie die sortierten Werte möchten, müssen Sie sie in a extrahieren
List
und sortieren.quelle
Dies kann nicht mit a erfolgen
Comparator
, da immer der Schlüssel der Karte zum Vergleichen angezeigt wird.TreeMap
kann nur nach dem Schlüssel sortieren.quelle
SortedMap
die die Sortierung nach Schlüsseln festgelegt ist) beginnersbook.com/2014/07/…Comparator
verwendet eine vorhandene Karte, um die zu sortierenden Werte abzurufen . Mit anderen Worten, es können keine beliebigen Werte sortiert werden, dieTreeMap
später eingegeben werden, sondern nur Werte, die bereits in der ursprünglichen Karte enthalten sind.Olof Antwort ist gut, aber es braucht eine weitere Sache , bevor es ist perfekt. In den Kommentaren unter seiner Antwort weist dacwe (korrekt) darauf hin, dass seine Implementierung gegen den Compare / Equals-Vertrag für Sets verstößt. Wenn Sie versuchen, Einträge aufzurufen oder zu entfernen, die eindeutig im Satz enthalten sind, erkennt der Satz dies nicht, da Einträge mit gleichen Werten in den Satz eingefügt werden können. Um dies zu beheben, müssen wir die Gleichheit zwischen den Schlüsseln testen:
"Beachten Sie, dass die Reihenfolge, die von einer sortierten Menge beibehalten wird (unabhängig davon, ob ein expliziter Komparator bereitgestellt wird oder nicht), mit gleich übereinstimmen muss, wenn die sortierte Menge die Set-Schnittstelle korrekt implementieren soll ... Die Set-Schnittstelle wird in Bezug auf die Gleichheitsoperation definiert , aber ein Element führt alle vergleiche unter Verwendung seines compareTo Menge sortierte (oder zu vergleichen) Verfahren, so dass zwei Elemente, die vom Standpunkt des sortierten Satzes gehalten werden, gleich nach dieser Methode sind, gleich .“ ( http://docs.oracle.com/javase/6/docs/api/java/util/SortedSet.html )
Da wir ursprünglich die Gleichheit übersehen haben, um die Menge zu zwingen, gleichwertige Einträge hinzuzufügen, müssen wir jetzt die Gleichheit in den Schlüsseln testen, damit die Menge tatsächlich den gewünschten Eintrag zurückgibt. Das ist ein bisschen chaotisch und definitiv nicht so, wie Sets verwendet werden sollten - aber es funktioniert.
quelle
Ich weiß, dass in diesem Beitrag speziell nach dem Sortieren einer TreeMap nach Werten gefragt wird, aber für diejenigen von uns, die sich nicht wirklich für die Implementierung interessieren, aber eine Lösung wünschen, die die Sammlung beim Hinzufügen von Elementen sortiert, würde ich mich über Feedback zu diesem TreeSet-basierten freuen Lösung. Zum einen lassen sich Elemente nicht einfach per Schlüssel abrufen, aber für den Anwendungsfall, den ich zur Hand hatte (die n Schlüssel mit den niedrigsten Werten zu finden), war dies keine Voraussetzung.
quelle
Viele Leute hören Ratschläge, List zu verwenden, und ich bevorzuge es auch
Hier sind zwei Methoden, mit denen Sie die Einträge der Karte nach ihren Werten sortieren können.
quelle