Stream Way для получения индекса первого элемента, соответствующего логическому

У меня есть List<Users>. Я хочу получить индекс (первого) пользователя в потоке с конкретным именем пользователя. Я не хочу на самом деле требовать, чтобы User был .equals() для описанного User, просто чтобы иметь одно и то же имя пользователя.

Я могу придумать уродливые способы сделать это (повторить и подсчитать), но похоже, что должен быть хороший способ сделать это, возможно, используя Streams. Пока что лучшее, что у меня есть:

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

Это не худший код, который я когда-либо писал, но это не здорово. Это также не так гибко, поскольку он полагается на наличие функции сопоставления с типом с функцией .equals(), которая описывает свойство, которое вы ищете; Я бы предпочел что-то, что могло бы работать для произвольного Function<T, Boolean>

Кто-нибудь знает как?

Ответ 1

Иногда в java нет pythonic zipWithIndex. Поэтому я наткнулся на что-то вроде этого:

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

В качестве альтернативы вы можете использовать zipWithIndex из protonpack библиотека

Примечание

Это решение может занять много времени, если users.get не является постоянной операцией времени.

Ответ 2

Попробуйте следующее:

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

Ответ 3

Вы можете попробовать библиотеку StreamEx, созданную Тагиром Валеевым. Эта библиотека имеет удобный метод #indexOf.

Это простой пример:

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);

Ответ 4

Решение без какой-либо внешней библиотеки

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;

просмотреть индекс приращения i, в то время как предикат ложен, следовательно, когда предикат истинен, я на 1 больше, чем сопоставленный предикат => i.get() -1