Поток Способ получения индекса первого элемента, совпадающего с логическим
У меня есть List<Users>
, Я хочу получить индекс (первого) пользователя в потоке с определенным именем пользователя. Я не хочу на самом деле требовать User
быть .equals()
некоторым описанным User
просто чтобы иметь то же имя пользователя.
Я могу придумать некрасивые способы сделать это (повторить и посчитать), но мне кажется, что должен быть хороший способ сделать это, возможно, с помощью Streams. Пока лучшее, что у меня есть:
int index = users.stream()
.map(user -> user.getName())
.collect(Collectors.toList())
.indexOf(username);
Это не худший код, который я когда-либо писал, но он не очень хорош. Это также не так гибко, так как оно зависит от наличия функции отображения для типа с .equals()
функция, которая описывает свойство, которое вы ищете; Я бы предпочел что-то, что могло бы работать на произвольную Function<T, Boolean>
Кто-нибудь знает как?
8 ответов
Изредка нет питона zipWithIndex
в Яве. Вот я и наткнулся на что-то подобное:
OptionalInt indexOpt = IntStream.range(0, users.size())
.filter(i -> searchName.equals(users.get(i)))
.findFirst();
В качестве альтернативы вы можете использовать zipWithIndex
из библиотеки протонпак
Заметка
Это решение может занять много времени, если users.get не работает с постоянным временем.
Попробуй это:
IntStream.range(0, users.size())
.filter(userInd-> users.get(userInd).getName().equals(username))
.findFirst()
.get();
Использование библиотеки Guava: int index =
Iterables.indexOf(users, u -> searchName.equals(u.getName()))
Вы можете попробовать библиотеку 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);
Решение без внешней библиотеки
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, пока предикат ложен, следовательно, когда предикат истинен, i на 1 больше, чем соответствующий предикат => i.get() -1
Здесь detectIndex
в библиотеке Eclipse Collections, который принимаетPredicate
.
int index = ListIterate.detectIndex(users, user -> username.equals(user.getName()));
Если у вас есть метод User
класс, который возвращает boolean
если username
совпадения можно использовать следующие:
int index = ListIterate.detectIndexWith(users, User::named, username);
Примечание: я являюсь коммиттером для коллекций Eclipse.
Найти, если присутствует, затем вернуть результат на основе этого.
- Узнайте, присутствует элемент или нет.
- Если присутствует индекс возврата, в противном случае возвращается -1
AtomicInteger index = new AtomicInteger();
int result = Arrays.stream(nums)
.peek((num) -> index.incrementAndGet())
.filter(num -> num == target)
.findFirst()
.orElse(-1);
return result == -1 ? result : index.get()-1;
AtomicInteger index = new AtomicInteger();
Начинается с 1, поэтому мы хотим получить индекс, поэтому мы вычитаем 1 из индекса
Больше короче
return Arrays.stream(nums)
.peek((num) -> index.incrementAndGet())
.filter(num -> num == target)
.findFirst()
.orElse(-1) == -1 ? -1 : index.get()-1;
Пути ко всему индексу Перебрать индекс и получить весь индекс
IntStream.range(0, list.size())
.filter(i -> Objects.equals(list.get(i), target)).forEach(System.out::println);