Ich habe eine Karte Map<K, V>
und mein Ziel ist es, die doppelten Werte zu entfernen und dieselbe Struktur Map<K, V>
erneut auszugeben . Falls der doppelte Wert gefunden wird, muss k
aus den beiden Schlüsseln ( k1
und k1
), die diese Werte enthalten, ein Schlüssel ( ) ausgewählt werden. Aus diesem Grund wird davon ausgegangen, dass das BinaryOperator<K>
Geben k
von k1
und k2
verfügbar ist.
Beispiel für Ein- und Ausgabe:
// Input
Map<Integer, String> map = new HashMap<>();
map.put(1, "apple");
map.put(5, "apple");
map.put(4, "orange");
map.put(3, "apple");
map.put(2, "orange");
// Output: {5=apple, 4=orange} // the key is the largest possible
Mein Versuch, etwas zu verwenden, Stream::collect(Supplier, BiConsumer, BiConsumer)
ist etwas sehr ungeschickt und enthält veränderbare Operationen wie Map::put
und, Map::remove
die ich vermeiden möchte:
// // the key is the largest integer possible (following the example above)
final BinaryOperator<K> reducingKeysBinaryOperator = (k1, k2) -> k1 > k2 ? k1 : k2;
Map<K, V> distinctValuesMap = map.entrySet().stream().collect(
HashMap::new, // A new map to return (supplier)
(map, entry) -> { // Accumulator
final K key = entry.getKey();
final V value = entry.getValue();
final Entry<K, V> editedEntry = Optional.of(map) // New edited Value
.filter(HashMap::isEmpty)
.map(m -> new SimpleEntry<>(key, value)) // If a first entry, use it
.orElseGet(() -> map.entrySet() // otherwise check for a duplicate
.stream()
.filter(e -> value.equals(e.getValue()))
.findFirst()
.map(e -> new SimpleEntry<>( // .. if found, replace
reducingKeysBinaryOperator.apply(e.getKey(), key),
map.remove(e.getKey())))
.orElse(new SimpleEntry<>(key, value))); // .. or else leave
map.put(editedEntry.getKey(), editedEntry.getValue()); // put it to the map
},
(m1, m2) -> {} // Combiner
);
Gibt es eine Lösung mit einer geeigneten Kombination Collectors
innerhalb eines Stream::collect
Anrufs (z. B. ohne veränderbare Operationen)?
quelle
Stream
s gemacht werden?Map::put
oderMap::remove
innerhalb derCollector
.BiMap
. Möglicherweise ein Duplikat von Doppelte Werte aus HashMap in Java entfernenAntworten:
Sie können Collectors.toMap verwenden
quelle
Versuchen Sie Folgendes: Auf einfache Weise werden Schlüssel und Wert umgekehrt, und dann wird der
toMap()
Kollektor mit der Zusammenführungsfunktion verwendet.quelle
map
kauft. Sie scheinen Schlüssel und Werte zu tauschen, so viel ist klar, aber worum geht es, Sie könnten das trotzdem beim Sammeln tun?swap(); collect(key, value, binOp);
stattcollect(value, key, binOp)
. Vielleicht muss ich das wirklich mal ausprobieren?Ich finde die Nicht-Streams-Lösung ausdrucksvoller:
Dies wird zusammen
Map.merge
mit Ihrer reduzierenden Bi-Funktion verwendet und dientLinkedHashMap
dazu, die Reihenfolge der ursprünglichen Einträge beizubehalten.quelle
Ich habe eine Möglichkeit gefunden,
Collectors
die zurückgegebene Karte nur zu verwenden, ohne sie erneut sammeln und weiterverarbeiten zu müssen. Die Idee ist:Gruppieren Sie die
Map<K, V>
zuMap<V, List<K>
.Reduzieren Sie die Verwendung der neuen Schlüssel (
List<K>
) .K
BinaryOperator<K>
Kehren Sie den
Map<V, K>
Rücken wieder zurMap<K, V>
Struktur um - was sicher ist, da sowohl Schlüssel als auch Werte als unterschiedlich garantiert sind.Der endgültige Code:
quelle
Ein weiterer Ansatz, um mit "Stream and Collectors.groupingBy" das gewünschte Ergebnis zu erzielen.
quelle