Karte, die in der Reihenfolge der Werte iteriert werden könnte

Lesezeit: 7 Minuten

Karte die in der Reihenfolge der Werte iteriert werden konnte
Rajat Gupta

Ich benötige eine Karte, die in absteigender Reihenfolge wiederholt werden kann Reihenfolge seiner Werte. Bietet eine der Standardbibliotheken wie Apache Commons oder Guava diese Art von Karte?

  • Die Standard-Java-Bibliothek hat eine Erweiterung der Map sortierte Schnittstelle namens SortedMap: docs.oracle.com/javase/7/docs/api/java/util/SortedMap.html Sie können dann einfach eine konkrete Umsetzung der SortedMap Schnittstelle

    – Jäger McMillen

    17. Januar ’12 um 14:53


  • Ich finde es seltsam, dass Sie die absteigende Reihenfolge von haben möchten Werte – willst du das wirklich oder meintest du? Schlüssel?

    – nd.

    17. Januar ’12 um 14:57

  • @nd: ja ich bin mir sicher das ich das wirklich will

    – Rajat Gupta

    17. Januar ’12 um 14:58 Uhr

  • SortedMap ordnet Schlüssel, nicht Werte – es wird in der ersten Zeile seiner Dokumentation angegeben.

    – Rostislav Matl

    17. Januar ’12 um 15:10 Uhr

1641702819 454 Karte die in der Reihenfolge der Werte iteriert werden konnte
Louis Wassermann

Ich würde dies mit Guave wie folgt machen:

Ordering<Map.Entry<Key, Value>> entryOrdering = Ordering.from(valueComparator)
  .onResultOf(new Function<Entry<Key, Value>, Value>() {
    public Value apply(Entry<Key, Value> entry) {
      return entry.getValue();
    }
  }).reverse();
// Desired entries in desired order.  Put them in an ImmutableMap in this order.
ImmutableMap.Builder<Key, Value> builder = ImmutableMap.builder();
for (Entry<Key, Value> entry : 
    entryOrdering.sortedCopy(map.entrySet())) {
  builder.put(entry.getKey(), entry.getValue());
}
return builder.build();
// ImmutableMap iterates over the entries in the desired order

  • Könnten Sie klarstellen, wie ich diesen WertComparator definiere?

    – Rajat Gupta

    17. Januar ’12 um 16:49

  • @user es ist Comparator<V> Sie in erster Linie verwenden möchten. Wenn Werte implementieren Comparable, dann kannst du verwenden Ordering.natural() statt Brauch valueComparator.

    – Xaerxess

    17. Januar ’12 um 18:04


  • Ordering.from(Ordering.natural())... zu einem veralteten Funktionsaufruf führt, gibt es eine alternative Methode, die stattdessen nach einem Komparatortypargument fragt. Meine Werte sind eigentlich von Typ Integer. Könnten Sie vorschlagen, welchen Komparator ich für die Sortierung ganzzahliger Werte übergeben sollte? Vielen Dank

    – Rajat Gupta

    18. Januar ’12 bei 4:37


  • Verwenden Sie nicht Ordering.from(Ordering.natural()), sondern verwenden Sie Ordering.natural() direkt.

    – Louis Wassermann

    18. Januar ’12 um 6:40

1641702819 464 Karte die in der Reihenfolge der Werte iteriert werden konnte
Xaerxess

Mit Guave gibt es einen noch saubereren Weg als die Antwort von @LoisWasserman – Bestellen in Kombination mit Functions.forMap:

Ordering.natural().reverse().nullsLast().onResultOf(Functions.forMap(map, null))

oder wenn die Werte nicht sind Comparable:

Ordering.fromComparator(yourComparator).reverse().nullsLast().onResultOf(Functions.forMap(map, null))

Ein Beispiel (mit erster Option – natürliche Reihenfolge):

final Map<String, String> map = ImmutableMap.of(
    "key 1", "value 1",
    "key 2", "value 2",
    "key 3", "another value",
    "key 4", "zero value");

final Ordering<String> naturalReverseValueOrdering =
    Ordering.natural().reverse().nullsLast().onResultOf(Functions.forMap(map, null));

System.out.println(ImmutableSortedMap.copyOf(map, naturalReverseValueOrdering));

Ausgänge:

{key 4=zero value, key 2=value 2, key 1=value 1, key 3=another value}

(Ich benutze ImmutableSortedMap hier aber Baumkarte kann auch verwendet werden, wenn Veränderlichkeit erforderlich ist.)

BEARBEITEN:

Bei identischen Werten (genauer bei zwei Werten, für die Comparator.compare(String v1, String v2) gibt 0 zurück. ImmutableSortedMap löst eine Ausnahme aus. Die Sortierung darf nicht zurückkehren, dh Sie sollten die Karte zuerst nach Werten und als nächstes nach Schlüsseln ordnen, wenn beide Werte gleich sind (Schlüssel sollen nicht gleich sein) mit Ordering.compound:

final Map<String, String> map = ImmutableMap.of(
    "key 1", "value 1",
    "key 2", "value 2",
    "key 3", "zero value",
    "key 4", "zero value");

final Ordering<String> reverseValuesAndNaturalKeysOrdering =
    Ordering.natural().reverse().nullsLast().onResultOf(Functions.forMap(map, null)) // natural for values
        .compound(Ordering.natural()); // secondary - natural ordering of keys

System.out.println(ImmutableSortedMap.copyOf(map, reverseValuesAndNaturalKeysOrdering));

druckt:

{key 3=zero value, key 4=zero value, key 2=value 2, key 1=value 1}

  • dies führt zu einer unzulässigen Argumentausnahme, falls zwei Schlüssel mit dem gleichen Wert gesetzt werden…

    – Rajat Gupta

    17. Januar ’12 um 18:50


  • @user das liegt daran, dass der Vergleich 0 zurückgibt (was auf Gleichheit hindeutet, was richtig ist) und ImmutableSortedMap dies als Ausnahmefall behandelt (was sollte es tun? Eintrag: key1=same_value zuerst oder besser key2=same_value Erste?). Komparator darf nicht in diesem Fall 0 zurückgeben, meine Antwort und mein Beispiel bearbeitet (aber denken Sie daran – es ist für Strings!).

    – Xaerxess

    17. Januar ’12 um 19:26


  • Mir ist diese Lösung wirklich grundsätzlich unangenehm, insbesondere weil Ihre ImmutableSortedMap nicht nur null für Schlüssel zurückgibt, die sich nicht in der Karte befinden: Sie schlägt vollständig fehl, weil der Komparator nicht zutrifft.

    – Louis Wassermann

    18. Januar ’12 um 0:13

  • @LouisWasserman ist das nicht genug, wenn es gleich ist map wird verwendet in Functions.forMap und ImmutableSortedMap.copyOf Konstrukteur?

    – Xaerxess

    18. Januar ’12 um 9:53

  • ich Überlegen die modifizierte Antwort ist richtig, aber als allgemeine Regel sollten Sie dies immer tun, wenn Sie vermeiden können, Code zu schreiben, der auf viele subtile Weise schief gehen kann.

    – Louis Wassermann

    20. Januar ’12 um 15:32

Einfache Methode, um eine unveränderliche Kopie Ihrer Karte zu erhalten, die nach absteigendem Wert sortiert ist. Entferne den Anruf an reverse() wenn Sie aufsteigende Reihenfolge wünschen. Erfordert Google Guave.

private Map<String, String> mapSortedByValues(Map<String, String> theMap) {
    final Ordering<String> ordering =
            Ordering.natural().reverse().nullsLast().onResultOf(Functions.forMap(theMap, null));

    return ImmutableSortedMap.copyOf(theMap, ordering);
}

Dies kann jetzt in einer einzigen Zeile mit Java 8-Streams:

map.entrySet().stream()
    .sorted(Comparator.comparing(Map.Entry::getValue))
    .forEach(...);

Ich denke der DualTreeBidiMap von Apache Commons Collections sollte dies ermöglichen, wahrscheinlich durch Iteration über die Rückgabe von inverseBidiMap().

Aber ich glaube nicht, dass dies doppelte Werte zulässt – wie der Name schon sagt, basiert die Struktur einfach auf der Beibehaltung zwei Bäume, was wirklich das einzige ist, was Sinn macht, da Werte in einer Karte keine Bedeutung für die Kartenstruktur haben.

  • Sie brauchen nicht zwei Bäume. Du könntest einen haben Map für die Schlüsselwerte und ein geordnetes List von Werten (oder von Map.Entrys wenn du das brauchst).

    – yshavit

    17. Januar ’12 um 15:25

  • @yshavit: Sie könnten, wenn Sie eine Listenstruktur haben, die sowohl automatisch geordnet ist als auch ein effizientes Einfügen und Löschen ermöglicht, was nicht einfach ist (ich denke, es kann mit einer Skip-Liste erfolgen). Warum die zusätzliche Komplexität, wenn Sie bereits einen Baum haben?

    – Michael Borgwardt

    17. Januar ’12 um 15:29

  • weil, wie Sie darauf hinweisen, es keine doppelten Werte zulässt. Wenn dies eine Anforderung ist, werden die zwei-Map Ansatz wird disqualifiziert. Und du brauchst kein List die die Bestellung für Sie verwaltet, können Sie die Bestellung auf Beilagen einfach manuell als Invariante sicherstellen. Aber wie auch immer, ich stimme zu, dass es komplexer ist und nur durchgeführt werden sollte, wenn Sie diese doppelten Werte benötigen.

    – yshavit

    17. Januar ’12 um 16:01

Karte die in der Reihenfolge der Werte iteriert werden konnte
Rostislav Matl

Wie wäre es, die Werte auch in TreeSet zu platzieren?

for(;;) { yourMap.put(key,value); }
SortedSet sortedValues = new TreeSet(yourMap.values());

oder

SortedSet sortedValues = new TreeSet();
for(;;) 
{
yourMap.put(key,value);
sortedValued.add(value);
}

  • Sie brauchen nicht zwei Bäume. Du könntest einen haben Map für die Schlüsselwerte und ein geordnetes List von Werten (oder von Map.Entrys wenn du das brauchst).

    – yshavit

    17. Januar ’12 um 15:25

  • @yshavit: Sie könnten, wenn Sie eine Listenstruktur haben, die sowohl automatisch geordnet ist als auch ein effizientes Einfügen und Löschen ermöglicht, was nicht einfach ist (ich denke, es kann mit einer Skip-Liste erfolgen). Warum die zusätzliche Komplexität, wenn Sie bereits einen Baum haben?

    – Michael Borgwardt

    17. Januar ’12 um 15:29

  • weil, wie Sie darauf hinweisen, es keine doppelten Werte zulässt. Wenn dies eine Anforderung ist, werden die zwei-Map Ansatz wird disqualifiziert. Und du brauchst kein List die die Bestellung für Sie verwaltet, können Sie die Bestellung auf Beilagen einfach manuell als Invariante sicherstellen. Aber wie auch immer, ich stimme zu, dass es komplexer ist und nur durchgeführt werden sollte, wenn Sie diese doppelten Werte benötigen.

    – yshavit

    17. Januar ’12 um 16:01

1641702820 820 Karte die in der Reihenfolge der Werte iteriert werden konnte
Piotr Gwiazda

Ich würde Einträge auf die Liste setzen und sie sortieren. Ich erinnere mich an keine Map, die nach Werten sortiert werden kann, nur nach Schlüsseln. Sie könnten BiMap von Guava verwenden, aber es erfordert die Einzigartigkeit der Werte.

Beispiel:

    public static void main(String[] args) {
        Map<String, String> map = new HashMap<String, String>() {{
            put("key1", "value1");
            put("key2", "value3");
            put("key3", "value4");
            put("key4", "value2");
        }};

        List<Map.Entry<String, String>> entries = new ArrayList<>(map.entrySet());
        Collections.sort(entries, new Comparator<Map.Entry<String, String>>() {

            @Override
            public int compare(Entry<String, String> o1,
                    Entry<String, String> o2) {
                if (o1.getValue() == null && o2.getValue() == null) return 0;
                if (o1.getValue() == null) return -1; //Nulls last
                return - o1.getValue().compareTo(o2.getValue());
            }
        });

    }

.

200470cookie-checkKarte, die in der Reihenfolge der Werte iteriert werden könnte

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy