1890 Stimmen

Sortieren einer Map<Schlüssel, Wert> nach Werten

Ich bin relativ neu in Java und stelle oft fest, dass ich eine Map<Key, Value> auf die Werte.

Da die Werte nicht eindeutig sind, muss ich die keySet in eine array und die Sortierung dieses Arrays durch Array-Sortierung mit einer benutzerdefinierter Komparator die nach dem mit dem Schlüssel verbundenen Wert sortiert.

Gibt es einen einfacheren Weg?

17voto

gdejohn Punkte 7132

Um dies mit den neuen Funktionen in Java 8 zu erreichen:

import static java.util.Map.Entry.comparingByValue;
import static java.util.stream.Collectors.toList;

<K, V> List<Entry<K, V>> sort(Map<K, V> map, Comparator<? super V> comparator) {
    return map.entrySet().stream().sorted(comparingByValue(comparator)).collect(toList());
}

Die Einträge werden mit Hilfe des angegebenen Komparators nach ihren Werten geordnet. Wenn Ihre Werte untereinander vergleichbar sind, ist kein expliziter Vergleicher erforderlich:

<K, V extends Comparable<? super V>> List<Entry<K, V>> sort(Map<K, V> map) {
    return map.entrySet().stream().sorted(comparingByValue()).collect(toList());
}

Die zurückgegebene Liste ist eine Momentaufnahme der angegebenen Karte zum Zeitpunkt des Aufrufs dieser Methode, so dass keine der beiden Listen spätere Änderungen an der anderen widerspiegelt. Für eine live iterable Ansicht der Karte:

<K, V extends Comparable<? super V>> Iterable<Entry<K, V>> sort(Map<K, V> map) {
    return () -> map.entrySet().stream().sorted(comparingByValue()).iterator();
}

Die zurückgegebene Iterable erstellt bei jeder Iteration einen neuen Schnappschuss der gegebenen Map, so dass sie, abgesehen von gleichzeitigen Änderungen, immer den aktuellen Zustand der Map wiedergibt.

17voto

Sujan Reddy A Punkte 112

Erstellen Sie einen angepassten Komparator und verwenden Sie ihn bei der Erstellung eines neuen TreeMap-Objekts.

class MyComparator implements Comparator<Object> {

    Map<String, Integer> map;

    public MyComparator(Map<String, Integer> map) {
        this.map = map;
    }

    public int compare(Object o1, Object o2) {

        if (map.get(o2) == map.get(o1))
            return 1;
        else
            return ((Integer) map.get(o2)).compareTo((Integer)     
                                                            map.get(o1));

    }
}

Verwenden Sie den folgenden Code in Ihrer Hauptfunktion

    Map<String, Integer> lMap = new HashMap<String, Integer>();
    lMap.put("A", 35);
    lMap.put("B", 75);
    lMap.put("C", 50);
    lMap.put("D", 50);

    MyComparator comparator = new MyComparator(lMap);

    Map<String, Integer> newMap = new TreeMap<String, Integer>(comparator);
    newMap.putAll(lMap);
    System.out.println(newMap);

出力します。

{B=75, D=50, C=50, A=35}

13voto

RoyalBigorno Punkte 11

Verwenden Sie einen generischen Komparator wie z.B.:

final class MapValueComparator<K,V extends Comparable<V>> implements Comparator<K> {
    private final Map<K,V> map;

    private MapValueComparator() {
        super();
    }

    public MapValueComparator(Map<K,V> map) {
        this();
        this.map = map;
    }

    public int compare(K o1, K o2) {
        return map.get(o1).compareTo(map.get(o2));
    }
}

13voto

Lyudmil Punkte 1153

Ich stimme zwar zu, dass die ständige Notwendigkeit, eine Karte zu sortieren, wahrscheinlich ein Geruch ist, aber ich denke, der folgende Code ist der einfachste Weg, dies zu tun, ohne eine andere Datenstruktur zu verwenden.

public class MapUtilities {

public static <K, V extends Comparable<V>> List<Entry<K, V>> sortByValue(Map<K, V> map) {
    List<Entry<K, V>> entries = new ArrayList<Entry<K, V>>(map.entrySet());
    Collections.sort(entries, new ByValue<K, V>());
    return entries;
}

private static class ByValue<K, V extends Comparable<V>> implements Comparator<Entry<K, V>> {
    public int compare(Entry<K, V> o1, Entry<K, V> o2) {
        return o1.getValue().compareTo(o2.getValue());
    }
}

}

Und hier ist ein peinlich unvollständiger Einheitstest:

public class MapUtilitiesTest extends TestCase {
public void testSorting() {
    HashMap<String, Integer> map = new HashMap<String, Integer>();
    map.put("One", 1);
    map.put("Two", 2);
    map.put("Three", 3);

    List<Map.Entry<String, Integer>> sorted = MapUtilities.sortByValue(map);
    assertEquals("First", "One", sorted.get(0).getKey());
    assertEquals("Second", "Two", sorted.get(1).getKey());
    assertEquals("Third", "Three", sorted.get(2).getKey());
}

}

Das Ergebnis ist eine sortierte Liste von Map.Entry-Objekten, aus der Sie die Schlüssel und Werte entnehmen können.

10voto

ciamej Punkte 6653

Anstelle der Verwendung von Collections.sort wie es einige tun, würde ich vorschlagen, die Arrays.sort . Was eigentlich Collections.sort ist in etwa so:

public static <T extends Comparable<? super T>> void sort(List<T> list) {
    Object[] a = list.toArray();
    Arrays.sort(a);
    ListIterator<T> i = list.listIterator();
    for (int j=0; j<a.length; j++) {
        i.next();
        i.set((T)a[j]);
    }
}

Sie ruft einfach toArray auf der Liste und verwendet dann Arrays.sort . Auf diese Weise werden alle Map-Einträge dreimal kopiert: einmal von der Map in die temporäre Liste (sei es eine LinkedList oder ArrayList), dann in das temporäre Array und schließlich in die neue Map.

Meine Lösung lässt diesen einen Schritt aus, da sie keine unnötige LinkedList erstellt. Hier ist der Code, generic-freundlich und Performance-optimiert:

public static <K, V extends Comparable<? super V>> Map<K, V> sortByValue(Map<K, V> map) 
{
    @SuppressWarnings("unchecked")
    Map.Entry<K,V>[] array = map.entrySet().toArray(new Map.Entry[map.size()]);

    Arrays.sort(array, new Comparator<Map.Entry<K, V>>() 
    {
        public int compare(Map.Entry<K, V> e1, Map.Entry<K, V> e2) 
        {
            return e1.getValue().compareTo(e2.getValue());
        }
    });

    Map<K, V> result = new LinkedHashMap<K, V>();
    for (Map.Entry<K, V> entry : array)
        result.put(entry.getKey(), entry.getValue());

    return result;
}

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X