用数据流方法获取匹配布尔值的第一个元素的索引

我有一个 List<Users>。我希望获得流中具有特定用户名的(第一个)用户的索引。我实际上不想要求 User是某些描述的 User.equals(),只是为了拥有相同的用户名。

我可以想到一些很难看的方法来做这件事(迭代和计数) ,但是感觉应该有一种很好的方法来做这件事,可能是通过使用 Streams。到目前为止,我最好的答案是:

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

这不是我写过的最烂的代码,但也不是很好。它也没有那么灵活,因为它依赖于有一个映射函数到一个具有 .equals()函数的类型,该函数描述您正在寻找的属性; 我更希望有一些能够适用于任意 Function<T, Boolean>的东西

有人知道怎么做吗?

113946 次浏览

Occasionally there is no pythonic zipWithIndex in java. So I came across something like that:

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

Alternatively you can use zipWithIndex from protonpack library

Note

That solution may be time-consuming if users.get is not constant time operation.

Try This:

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

You can try StreamEx library made by Tagir Valeev. That library has a convenient #indexOf method.

This is a simple example:

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

A solution without any external library

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 increment index i while predicate is false hence when predicate is true i is 1 more than matched predicate => i.get() -1

Using Guava library: int index = Iterables.indexOf(users, u -> searchName.equals(u.getName()))

There is the detectIndex method in the Eclipse Collections library which takes a Predicate.

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

If you have a method on User class which returns boolean if username matches you can use the following:

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

Note: I a committer for Eclipse Collections