Java 8 Eindeutig nach Eigenschaft

Lesezeit: 5 Minuten

Java 8 Eindeutig nach Eigenschaft
RichK

Wie kann ich in Java 8 eine Sammlung mithilfe von filtern? Stream API durch Überprüfung der Unterscheidbarkeit einer Eigenschaft jedes Objekts?

Zum Beispiel habe ich eine Liste von Person Objekt und ich möchte Personen mit demselben Namen entfernen,

persons.stream().distinct();

Verwendet die standardmäßige Gleichheitsprüfung für a Person Objekt, also brauche ich so etwas wie

persons.stream().distinct(p -> p.getName());

Leider die distinct() Methode hat keine solche Überladung. Ohne die Gleichheitsprüfung in der zu ändern Person Klasse ist es möglich, dies kurz und bündig zu tun?

Java 8 Eindeutig nach Eigenschaft
wa’eve’

Eine Alternative wäre, die Personen mit dem Namen als Schlüssel in einer Karte zu platzieren:

persons.collect(Collectors.toMap(Person::getName, p -> p, (p, q) -> p)).values();

Beachten Sie, dass die Person, die behalten wird, im Falle eines doppelten Namens die erste ist, auf die Sie stoßen.

  • @skiwi: Glaubst du, es gibt eine Möglichkeit, dies zu implementieren? distinct() ohne diesen Overhead? Wie würde eine Implementierung wissen, ob sie ein Objekt schon einmal gesehen hat, ohne sich tatsächlich an alle unterschiedlichen Werte zu erinnern, die sie gesehen hat? Also der Aufwand von toMap und distinct ist sehr wahrscheinlich gleich.

    – Holger

    19. Mai 2014 um 8:38 Uhr


  • @Holger Da habe ich mich vielleicht geirrt, da ich nicht an den Overhead gedacht hatte distinct() selbst schafft.

    – skiwi

    19. Mai 2014 um 8:50 Uhr

  • Und offensichtlich bringt es die ursprüngliche Reihenfolge der Liste durcheinander

    – Philipp

    7. November 2016 um 18:56 Uhr

  • @Philipp: könnte durch Wechseln zu behoben werden persons.collect(toMap(Person::getName, p -> p, (p, q) -> p, LinkedHashMap::new)).values();

    – Holger

    17. November 2017 um 8:02 Uhr

  • @DanielEarwicker Bei dieser Frage geht es um “durch Eigentum getrennt”. Es würde erfordern, dass der Stream sortiert wird durch dasselbe Grundstück, davon profitieren zu können. Erstens hat das OP nie angegeben, dass der Stream überhaupt sortiert ist. Zweitens können Streams nicht erkennen, ob sie sortiert sind durch eine bestimmte Eigenschaft. Drittens gibt es keine echte Stream-Operation “durch Eigenschaft getrennt”, um das zu tun, was Sie vorschlagen. Ferner gibt es in der Praxis nur zwei Möglichkeiten, einen solchen sortierten Strom zu erhalten. Eine sortierte Quelle (TreeSet) die sowieso schon deutlich ist bzw sorted auf dem Stream, der auch alle Elemente puffert.

    – Holger

    30. September 2018 um 10:36 Uhr

  • Dies nennt man die Schwartzsche Transformation

    – Stuart Caie

    16. Mai 2014 um 18:07 Uhr

  • @StuartCaie Nicht wirklich … es gibt keine Memoisierung, und der Punkt ist nicht die Leistung, sondern die Anpassung an die vorhandene API.

    – Marko Topolnik

    16. Mai 2014 um 20:21 Uhr


  • com.google.common.base.Equivalence.wrap(S) und com.google.common.base.Equivalence.Wrapper.get() könnten auch helfen.

    – bjmi

    30. Januar 2017 um 12:52 Uhr


  • Sie könnten die Wrapper-Klasse generisch und durch eine Schlüsselextraktionsfunktion parametrisieren.

    – Lii

    28. Juli 2017 um 2:00 Uhr

  • Um den Vorschlag von @bjmi zu erweitern, hier ein Anwendungsbeispiel: persons.stream().map(Equivalence.equals().onResultOf(Person::getName)::wrap).distinct().map(Equivalence.Wrapper::get)....

    – super_erdferkel

    6. Oktober 2021 um 19:52 Uhr

1646631430 781 Java 8 Eindeutig nach Eigenschaft
Santhosh

Eine andere Lösung, mit Set. Ist vielleicht nicht die ideale Lösung, aber es funktioniert

Set<String> set = new HashSet<>(persons.size());
persons.stream().filter(p -> set.add(p.getName())).collect(Collectors.toList());

Oder wenn Sie die ursprüngliche Liste ändern können, können Sie verwenden entfernenWenn Methode

persons.removeIf(p -> !set.add(p.getName()));

  • Dies ist die beste Antwort, wenn Sie keine Bibliotheken von Drittanbietern verwenden!

    – Manoj Shrestha

    22. Dezember 2018 um 1:08 Uhr


  • Verwenden der genialen Idee, dass Set.add true zurückgibt, wenn diese Menge das angegebene Element nicht bereits enthält. +1

    – Luvie

    31. Juli 2019 um 10:27 Uhr

  • Ich glaube, diese Methode funktioniert nicht für die parallele Stream-Verarbeitung, da sie nicht Thread-sicher ist.

    – Lobo

    25. März 2020 um 12:32 Uhr

  • @LoBo Wahrscheinlich nicht. Dies ist nur eine Idee, die für einfache Fälle funktionieren wird. Benutzer können es für Thread-Sicherheit/Parallelität erweitern.

    – Santhosh

    27. März 2020 um 17:17 Uhr

  • Interessanter Ansatz, sieht aber wie ein Anti-Pattern aus, um eine externe Sammlung (Set) zu modifizieren, während ein Stream auf eine andere Sammlung (Personen) gefiltert wird …

    – Justin Rowe

    8. Mai 2020 um 9:10 Uhr

1646631430 857 Java 8 Eindeutig nach Eigenschaft
josketres

Es gibt einen einfacheren Ansatz, der ein TreeSet mit einem benutzerdefinierten Komparator verwendet.

persons.stream()
    .collect(Collectors.toCollection(
      () -> new TreeSet<Person>((p1, p2) -> p1.getName().compareTo(p2.getName())) 
));

  • Dies ist die beste Antwort, wenn Sie keine Bibliotheken von Drittanbietern verwenden!

    – Manoj Shrestha

    22. Dezember 2018 um 1:08 Uhr


  • Verwenden der genialen Idee, dass Set.add true zurückgibt, wenn diese Menge das angegebene Element nicht bereits enthält. +1

    – Luvie

    31. Juli 2019 um 10:27 Uhr

  • Ich glaube, diese Methode funktioniert nicht für die parallele Stream-Verarbeitung, da sie nicht Thread-sicher ist.

    – Lobo

    25. März 2020 um 12:32 Uhr

  • @LoBo Wahrscheinlich nicht. Dies ist nur eine Idee, die für einfache Fälle funktionieren wird. Benutzer können es für Thread-Sicherheit/Parallelität erweitern.

    – Santhosh

    27. März 2020 um 17:17 Uhr

  • Interessanter Ansatz, sieht aber wie ein Anti-Pattern aus, um eine externe Sammlung (Set) zu modifizieren, während ein Stream auf eine andere Sammlung (Personen) gefiltert wird …

    – Justin Rowe

    8. Mai 2020 um 9:10 Uhr

Können wir auch verwenden RxJava (sehr kraftvoll reaktive Erweiterung Bücherei)

Observable.from(persons).distinct(Person::getName)

oder

Observable.from(persons).distinct(p -> p.getName())

  • Rx ist großartig, aber das ist eine schlechte Antwort. Observable ist Push-basiert, während Stream ist Pull-basiert. stackoverflow.com/questions/30216979/…

    – sdgfsdh

    1. Juni 2017 um 16:25 Uhr

  • Die Frage fragt nach einer Java8-Lösung, die nicht unbedingt Stream verwendet. Meine Antwort zeigt, dass die Java8-Stream-API weniger leistungsstark ist als die RX-API

    – Frhack

    2. Juni 2017 um 0:41 Uhr

  • Verwenden Reaktores wird sein Flux.fromIterable(persons).distinct(p -> p.getName())

    – Ritesch

    16. August 2017 um 14:53 Uhr

  • Die Frage lautet wörtlich “mit der Stream API”, nicht “nicht unbedingt Stream verwenden”. Das heißt, dies ist eine großartige Lösung für das XY-Problem, den Stream auf unterschiedliche Werte zu filtern.

    – M. Justin

    2. Mai 2018 um 16:43 Uhr

963220cookie-checkJava 8 Eindeutig nach Eigenschaft

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

Privacy policy