Is There a Concise Way to Iterate Over a Stream With Indices in Java 8

Is there a concise way to iterate over a stream with indices in Java 8?

The cleanest way is to start from a stream of indices:

String[] names = {"Sam", "Pamela", "Dave", "Pascal", "Erik"};
IntStream.range(0, names.length)
.filter(i -> names[i].length() <= i)
.mapToObj(i -> names[i])
.collect(Collectors.toList());

The resulting list contains "Erik" only.


One alternative which looks more familiar when you are used to for loops would be to maintain an ad hoc counter using a mutable object, for example an AtomicInteger:

String[] names = {"Sam", "Pamela", "Dave", "Pascal", "Erik"};
AtomicInteger index = new AtomicInteger();
List<String> list = Arrays.stream(names)
.filter(n -> n.length() <= index.incrementAndGet())
.collect(Collectors.toList());

Note that using the latter method on a parallel stream could break as the items would not necesarily be processed "in order".

Get Index while iterating list with stream

You haven't provided the signature of buildRate, but I'm assuming you want the index of the elements of guestList to be passed in first (before ageRate). You can use an IntStream to get indices rather than having to deal with the elements directly:

List<Rate> rateList = IntStream.range(0, guestList.size())
.mapToObj(index -> buildRate(index, ageRate, guestRate, guestList.get(index)))
.collect(Collectors.toList());

Java - cleanest way to iterate over a stream keeping track of index

The simple way

List<Foo> result = new ArrayList<>(list);
result.remove(i);

For long lists and low values of i, this might be a bit slow because it has to shift the tail elements left, however for brevity and clarity you can't beat it.

The stream way

You can use a stream and keep track of the index by using AtomicInteger, whose reference is effectively final, but whose value may be changed:

AtomicInteger index = new AtomicInteger();
List<Foo> result = list.stream()
.filter(x -> index.getAndIncrement() != i)
.collect(toList());

For large lists this may be faster since no shift left is required, and you can do other stuff in the stream in the one operation.

Of course if you want to filter many elements based on their index, you can do that without any performance hit.

With a stream, you might not even need the list if you just want to do stuff with the result directly:

list.stream()
.filter(x -> index.getAndIncrement() != i)
.forEach(foo -> {doSomething with foo});

How to iterate over a list of maps with indexes using java stream

As an advocate for streams, I personally don't like using them here. But I will anyhow:

IntStream.range(0, mapList.size())
.forEach(index -> {
Map<String, String> map = mapList.get(index);
System.out.println("ListOfMaps[" + index + "]" ...);
})

Java 8 forEach with index

Since you are iterating over an indexable collection (lists, etc.), I presume that you can then just iterate with the indices of the elements:

IntStream.range(0, params.size())
.forEach(idx ->
query.bind(
idx,
params.get(idx)
)
)
;

The resulting code is similar to iterating a list with the classic i++-style for loop, except with easier parallelizability (assuming, of course, that concurrent read-only access to params is safe).

Java8 forEach with index

I found a util method in eclipse collections with this post Is there a concise way to iterate over a stream with indices in Java 8?

https://www.eclipse.org/collections/javadoc/7.0.0/org/eclipse/collections/impl/utility/Iterate.html#forEachWithIndex-java.lang.Iterable-org.eclipse.collections.api.block.procedure.primitive.ObjectIntProcedure-

Iterate.forEachWithIndex(people, (Person person, int index) -> LOGGER.info("Index: " + index + " person: " + person.getName()));

The implementation https://github.com/eclipse/eclipse-collections/blob/master/eclipse-collections/src/main/java/org/eclipse/collections/impl/utility/internal/IteratorIterate.java is very similar to my util method:

public static <T> void forEach(@NonNull Iterable<T> iterable, @NonNull ObjIntConsumer<T> consumer) {
int i = 0;
for (T t : iterable) {
consumer.accept(t, i++);
}
}

Loop index in java 8

You could use an IntStream for that... but why should you? It looks basically the same as what you wrote, but has some overhead due to the IntStream which is not really needed here.

IntStream.range(0, list.size())
.forEach(i -> {
if (i % 1000 == 0) {
doSomething();
}
doSomethingElse(list.get(i));
});

Without knowing what doSomething or doSomethingElse do, it's hard to make a better proposal. Maybe you want to (or should?) partition your list beforehand?



Related Topics



Leave a reply



Submit