Wie filtert man eine Karte nach ihren Werten in Java 8?

Lesezeit: 4 Minuten

Benutzeravatar von Nazila
Nazila

Ich habe eine Karte, in der die Werte Zeichenfolgen und die Schlüssel Listen sind:

Map<String, List<BoMLine>> materials

Ich möchte diese Karte nach ihren Werten filtern; etwas wie das:

materials.entrySet().stream()
       .filter(a -> a.getValue().stream()
           .filter(l -> MaterialDao.findMaterialByName(l.getMaterial()).ispresent)

Aber es funktioniert nicht für mich. Hat jemand eine Idee?

Benutzeravatar von Eran
Eran

Wenn ich Ihre Filterkriterien richtig verstehe, möchten Sie überprüfen, ob die gefilterten Stream Sie haben aus dem Wert produziert List irgendwelche Elemente hat, und wenn ja, übergeben Sie die entsprechenden Map Eingang zum Ausgang Map.

Map<String, List<BoMLine>>
    filtered = materials.entrySet()
                        .stream()
                        .filter(a->a.getValue()
                                    .stream()
                                    .anyMatch(l->MaterialDao.findMaterialByName(l.getMaterial())))
                        .collect(Collectors.toMap(e->e.getKey(),e->e.getValue()));

Dies ist vorausgesetzt MaterialDao.findMaterialByName(l.getMaterial()) gibt a zurück boolean.

  • Ich bin mir meiner Lösung nicht sicher und es funktioniert nicht, wenn ich sie sammeln möchte, um “e” zuzuordnen, ist keine Karte, sondern nur ein Objekt

    – Nazila

    1. November 2015 um 7:25 Uhr

  • @Nazila e ist ein Map.Entry<String,List<BoMLine>>. Ich habe einige dumme Syntaxfehler im Aufruf von gemacht collect. Siehe bearbeitete Antwort.

    – Eran

    1. November 2015 um 7:33 Uhr

  • Sie müssen nicht verwenden filter()übergeben Sie einfach das Prädikat als Argument an anyMatch().

    – fps

    1. November 2015 um 12:59 Uhr


  • @FedericoPeraltaSchaffner Danke. Ich habe aus dem Gedächtnis geantwortet, ohne die API zu überprüfen. Ich werde es reparieren.

    – Eran

    1. November 2015 um 13:03 Uhr

  • @Eran Ich habe versucht, mit demselben zu filtern, aber wenn ich einen Nullwert in einem der Objekte habe, wird eine Nullzeiger-Ausnahme ausgelöst. Wie kann ich das vermeiden?

    – Bravo

    13. Dezember 2021 um 18:22 Uhr

Im Allgemeinen können Sie eine Karte folgendermaßen nach ihren Werten filtern:

static <K, V> Map<K, V> filterByValue(Map<K, V> map, Predicate<V> predicate) {
    return map.entrySet()
            .stream()
            .filter(entry -> predicate.test(entry.getValue()))
            .collect(Collectors.toMap(Entry::getKey, Entry::getValue));
}

Nennen Sie es so:

Map<String, Integer> originalMap = new HashMap<>();
originalMap.put("One", 1);
originalMap.put("Two", 2);
originalMap.put("Three", 3);

Map<String, Integer> filteredMap = filterByValue(originalMap, value -> value == 2);

Map<String, Integer> expectedMap = new HashMap<>();
expectedMap.put("Two", 2);

assertEquals(expectedMap, filteredMap);

  • Falls sich jemand wundert, Entry::getKey & Entry::getValue im obigen Ausschnitt bezieht sich tatsächlich auf java.util.Map.Entry::getKey (müssen import java.util.Map oder java.util.Map.Entry dafür)

    – y2k-shubham

    8. August 2022 um 10:05 Uhr


Alle vorherigen Antworten bieten eine Lösung, die eine neue schafft Map. Dies kann ineffizient sein, wenn Sie nur wenige Einträge entfernen möchten.

Im Folgenden werden die Elemente aus der entfernt bestehende Map:

Map<String, Integer> myMap = new HashMap<>();
myMap.put("One", 1);
myMap.put("Two", 2);
myMap.put("Three", 3);

myMap.keySet().removeAll(
        myMap.entrySet().stream()
           .filter(a->a.getValue().equals(2))
                   .map(e -> e.getKey()).collect(Collectors.toList()));

System.out.println(myMap);

Drucke:

{One=1, Three=3}

Wie funktioniert es? Es sammelt alle Schlüssel die in ein Provisorium entfernt werden müssen Listund entfernt sie dann aus dem Original Map auf einmal. Eine temporäre List ist erforderlich, weil das Ändern von a Map macht Streams und Iteratoren ungültig. Allerdings wird neu gebaut Map ist möglicherweise ein viel kostspieligerer Vorgang als der Bau einer List.

Wenn Sie viele Einträge entfernen möchten (50 % oder mehr), dann ist es besser, einen neuen zu erstellen Map In der Tat.

Benutzeravatar von Nazila
Nazila

Ich habe es endlich geschafft. Mein zweiter Filter war völlig nutzlos. Die Antwort lautet wie folgt:

Map<String, List<BoMLine>>
filtered = materials.entrySet()
                    .stream()
                    .filter(a -> a
                      .getValue()
                       .stream()
                        .allMatch(
                            b -> MaterialDao.findMaterialByName(
                                    b.getMaterial()).isPresent()))
            .collect(Collectors.toMap(p -> p.getKey(), p -> p.getValue()))

Meiner bescheidenen Meinung nach könnte einer der prägnantesten Java-8-Codes so aussehen:

public Map<String, ReportPlaceholderValue> getAllPlaceholders() {
    Map<String, ReportPlaceholderValue> result = chamberDetailsPlaceHolders;

    result.entrySet().stream().filter( e -> !(e.getValue() instanceof StringReportPlaceholderValue) )
       .map( Map.Entry::getKey )
       .collect( Collectors.toList() ).forEach( result.keySet()::remove );

    return result;
}

1449870cookie-checkWie filtert man eine Karte nach ihren Werten in Java 8?

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

Privacy policy