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
How to Convert Java.Util.Date to Java.Sql.Date
List of Java Class File Format Major Version Numbers
Java Error: Comparison Method Violates Its General Contract
How to Tell Jackson to Ignore a Field During Serialization If Its Value Is Null
Bringing Jfilechooser on Top of All Windows
When to Choose Checked and Unchecked Exceptions
Java Https Client Certificate Authentication
Spring @Transactional Not Auto Rolling Back During Unchecked Exception
What's the Reason I Can't Create Generic Array Types in Java
Error: the Processing Instruction Target Matching "[Xx][Mm][Ll]" Is Not Allowed
Overloaded Method Selection Based on the Parameter'S Real Type
How to Escape Text For Regular Expression in Java
Swing: Link Toggle Buttons Together With a Button Group, Along With Corresponding Menu Items
How to Get Rid of Accents and Convert a Whole String to Regular Letters