关于java:Stream获取与布尔值匹配的第一个元素的索引的方法

Stream Way to get index of first element matching boolean

我有一个List。 我想获取具有特定用户名的流中(第一个)用户的索引。 我并不想实际上将User设置为某些描述的User.equals(),只是具有相同的用户名。

我可以想到执行此操作的丑陋方法(重复和计数),但感觉应该有一种不错的方法(可能是通过使用Streams来执行此操作)。 到目前为止,我拥有的最好的是:

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

这不是我编写过的最糟糕的代码,但这不是很好。 它也不是那么灵活,因为它依赖于一个具有.equals()函数的类型的映射函数,该函数描述了您要查找的属性。 我宁愿有一些可以对任意Function起作用的东西

有人知道吗?


有时Java中没有pythonic zipWithIndex。所以我遇到了这样的事情:

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

或者,您可以使用来自protonpack库的zipWithIndex

注意

如果users.get不是恒定时间操作,则该解决方案可能很耗时。


尝试这个:

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


您可以尝试Tagir Valeev制作的StreamEx库。该库具有方便的#indexOf方法。

这是一个简单的示例:

1
2
3
4
5
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);

没有任何外部库的解决方案

1
2
3
4
5
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;

谓词为false时的peek增量索引i,因此当谓词为true时,我比匹配的谓词多1 => i.get() -1


Eclipse Collections库中有一个detectIndex方法,该方法采用Predicate

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

如果User类上有一个方法,如果username匹配,则该方法返回boolean,则可以使用以下方法:

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

注意:我是Eclipse Collections的提交者


使用Guava库:int index =
Iterables.indexOf(users, u -> searchName.equals(u.getName()))