Stream Methode, um den Index des ersten Elements zu erhalten, das mit dem booleschen Wert übereinstimmt

Lesezeit: 5 Minuten

Ich habe ein List<Users>. Ich möchte den Index des (ersten) Benutzers im Stream mit einem bestimmten Benutzernamen erhalten. Ich möchte das eigentlich nicht verlangen User sein .equals() zu einigen beschrieben Usernur um den gleichen Benutzernamen zu haben.

Ich kann mir hässliche Möglichkeiten vorstellen, dies zu tun (Iterate und Count), aber es scheint, als ob es eine nette Möglichkeit geben sollte, dies zu tun, wahrscheinlich durch die Verwendung von Streams. Das Beste, was ich bisher habe, ist:

int index = users.stream()
    .map(user -> user.getName())
    .collect(Collectors.toList())
    .indexOf(username);

Das ist nicht der schlechteste Code, den ich je geschrieben habe, aber er ist nicht großartig. Es ist auch nicht so flexibel, da es darauf angewiesen ist, dass es eine Zuordnungsfunktion zu einem Typ mit a gibt .equals() Funktion, die die gesuchte Eigenschaft beschreibt; Ich hätte viel lieber etwas, das für Willkür funktionieren könnte Function<T, Boolean>

Weiß jemand wie?

  • Warum ist “wiederholen” hässlich?

    –Andreas

    15. August 2016 um 21:45 Uhr

  • Streams und Indizierung passen nicht gut zusammen. An diesem Punkt ist es normalerweise besser, auf eine Schleife im alten Stil zurückzugreifen.

    – Louis Wassermann

    15. August 2016 um 21:46 Uhr


  • @Andreas Was ich an Streams mag, ist die Trennung der sammlungsbezogenen Logik von der spezifischen Sache, die gefragt wird. In diesem Fall gibt es eine Menge verschiedener Fragen, die gestellt werden könnten, die nur vom Kern abweichen Function<T, Boolean>also sollte es eine Möglichkeit geben, damit umzugehen, die es von der allgemeinen Sammlungslogik abstrahiert.

    – Eduard Peters

    15. August 2016 um 21:55 Uhr

  • @Andreas Weil Sie dort den gesamten strukturbezogenen Code manuell beschreiben, anstatt diesen zu unterteilen. Zu der anderen Frage, das habe ich gerade vergessen Predicate war eine Sache.

    – Eduard Peters

    15. August 2016 um 22:09 Uhr

  • Saubere Java 11-Lösung: int index = users.stream().map(User::getName).takeWhile(not(username::equals)).count();

    – Klitos Kyriacou

    9. November 2018 um 17:11 Uhr

Benutzer-Avatar
vsminkow

Gelegentlich gibt es keine Pythonik zipWithIndex auf Java. Also ich bin auf sowas gestoßen:

OptionalInt indexOpt = IntStream.range(0, users.size())
     .filter(i -> searchName.equals(users.get(i)))
     .findFirst();

Alternativ können Sie verwenden zipWithIndex aus Protonenpaket Bibliothek

Notiz

Diese Lösung kann zeitaufwändig sein, wenn users.get kein Dauerbetrieb ist.

  • Das funktioniert. Ich könnte das Paar auch überspringen, indem ich einfach den Benutzer mit dem angegebenen Index in der Filteroperation nachschlage … nicht sicher, ob das besser oder schlechter ist.

    – Eduard Peters

    15. August 2016 um 21:38 Uhr

  • @EdwardPeters Es ist definitiv besser. Zumindest wird dadurch zusätzlicher Speicherverkehr eliminiert

    – Wsminkow

    15. August 2016 um 21:39 Uhr


  • @vsminkov, Sie sollten hier vorsichtig sein. Niemand hat gesagt, dass die Liste O(1)-Zugriff hat.

    – Service

    15. August 2016 um 21:46 Uhr

  • @SerCe fair genug. Die andere Möglichkeit besteht darin, einen benutzerdefinierten Spliterator zu implementieren, wie es Protonpack tut. Ich werde eine Notiz machen

    – Wsminkow

    15. August 2016 um 21:50 Uhr


Benutzer-Avatar
AmanSinghal

Versuche dies:

IntStream.range(0, users.size())
    .filter(userInd-> users.get(userInd).getName().equals(username))
    .findFirst()
    .getAsInt();

  • Das bringt mir den Benutzer, aber nicht den Index

    – Eduard Peters

    15. August 2016 um 21:34 Uhr

  • Stimme Ihnen zu, können Sie mir bitte mit Vorschlägen helfen, diesen Anwendungsfall hier zu handhaben.

    – AmanSinghal

    15. August 2016 um 21:45 Uhr

  • Anstatt von get()verwenden orElse(-1)wie es andere Index-of-Operationen tun.

    – Brian Götz

    15. August 2016 um 21:53 Uhr

  • aber der Code wird hier abstürzen. users.get(userInd). getName() wenn der zurückgegebene Benutzer null ist. Kümmert sich die Stream-API auch um NullPointerException?

    – AmanSinghal

    15. August 2016 um 21:55 Uhr

  • @AmanSinghal IMO, Sie sollten keine Nullwerte in Listen haben, aber leere Listen oder Listen, denen ein angeforderter Name fehlt, sind sinnvoll. Wenn Sie eine NPE erhalten, weil jemand einen Nullwert in eine Liste eingetragen hat, ist das seine Schuld

    – Eduard Peters

    15. August 2016 um 22:20 Uhr

Verwendung der Guava-Bibliothek: int index =
Iterables.indexOf(users, u -> searchName.equals(u.getName()))

  • die am besten lesbare Lösung und Chancen guave – wie commons-lang – ist bereits in Ihrem POM 😉 IMHO eleganter als ein IntStream!

    – Benutzer1075613

    28. November 2020 um 2:42 Uhr

Du kannst es versuchen StreamEx Bibliothek erstellt von Tagir Walejew. Diese Bibliothek hat eine praktische #indexOf-Methode.

Dies ist ein einfaches Beispiel:

List<User> users = asList(new User("Vas"), new User("Innokenty"), new User("WAT"));
long index = StreamEx.of(users)
        .indexOf(user -> user.name.equals("Innokenty"))
        .getAsLong();
System.out.println(index);

Benutzer-Avatar
Hibor

Eine Lösung ohne externe Bibliothek

AtomicInteger i = new AtomicInteger(); // any mutable integer wrapper
int index = users.stream()
    .peek(v -> i.incrementAndGet())
    .anyMatch(user -> user.getName().equals(username)) ? // your predicate
    i.get() - 1 : -1;

Peek erhöht den Index i, während das Prädikat falsch ist, daher ist i, wenn das Prädikat wahr ist, um 1 größer als das übereinstimmende Prädikat => i.get() -1

  • Dies ist ein gefährlicher Ansatz, da Streams je nach Quelle parallel verarbeitet werden können, wobei der Index in diesem Fall vollständig deaktiviert sein kann. Sie sollten hinzufügen .sequential() Vor .peek() um dies zuverlässig zu machen.

    – Pawel Weselow

    15. Dezember 2021 um 22:58 Uhr

Benutzer-Avatar
Donald Rab

Dort ist der detectIndex Methode in der Eclipse-Sammlungen Bibliothek, die eine nimmt Predicate.

int index = ListIterate.detectIndex(users, user -> username.equals(user.getName()));

Wenn Sie eine Methode haben User Klasse, die zurückkehrt boolean wenn username Streichhölzer können Sie Folgendes verwenden:

int index = ListIterate.detectIndexWith(users, User::named, username);

Hinweis: Ich bin ein Committer für Eclipse Collections

  • Dies ist ein gefährlicher Ansatz, da Streams je nach Quelle parallel verarbeitet werden können, wobei der Index in diesem Fall vollständig deaktiviert sein kann. Sie sollten hinzufügen .sequential() Vor .peek() um dies zuverlässig zu machen.

    – Pawel Weselow

    15. Dezember 2021 um 22:58 Uhr

1217090cookie-checkStream Methode, um den Index des ersten Elements zu erhalten, das mit dem booleschen Wert übereinstimmt

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

Privacy policy