I have a List<Users>. I want to get the index of the (first) user in the stream with a particular username. I don't want to actually require the User to be .equals() to some described User, just to have the same username.
I can think of ugly ways to do this (iterate and count), but it feels like there should be a nice way to do this, probably by using Streams. So far the best I have is:
int index = users.stream() .map(user -> user.getName()) .collect(Collectors.toList()) .indexOf(username); Which isn't the worst code I've ever written, but it's not great. It's also not that flexible, as it relies on there being a mapping function to a type with a .equals() function that describes the property you're looking for; I'd much rather have something that could work for arbitrary Function<T, Boolean>
Anyone know how?
66 Answers
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.
4Try This:
IntStream.range(0, users.size()) .filter(userInd-> users.get(userInd).getName().equals(username)) .findFirst() .getAsInt(); 5Using Guava library: int index = Iterables.indexOf(users, u -> searchName.equals(u.getName()))
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
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