Home > Software design >  How to iterate over a Java stream with index and value together?
How to iterate over a Java stream with index and value together?

Time:12-16

I'd like to have something like the following:

List<Something> list = ...;
new IndexStream(list).forEach(i, s -> System.println("Index: "   i   ". Something: "   s));

I'm also ok with some mapping to pairs:

new IndexStream(list).forEach(pair -> System.println("Index: "   pair.left()   ". Something: "   pair.right()));

Would also be nice if I could just wrap another stream and added the counting:

new IndexStream(anotherStream).forEach(pair -> System.println("Index: "   pair.left()   ". Something: "   pair.right()));

Any idea how to achieve this? Perhaps there's a library for that?

CodePudding user response:

Using streams, IntStream.range(0, list.size()).forEach(i -> /* get element with list.get(i) */) is the standard way to do this.

Your example is probably not everything that you're trying to do; but you could achieve what you've shown here using plain old loops, which are less restrictive than forEach. For example, using an indexed for loop:

for (int i = 0; i < list.size();   i) {
  Something e = list.get(i);
  // ...
}

Or use an enhanced for loop, managing the index yourself:

int i = 0;
for (Something e : list) {
  // ...
  i  ;
}

Or use a ListIterator:

ListIterator<Something> lit = list.listIterator();
while (lit.hasNext()) {
  int i = lit.nextIndex();
  Something e = lit.next();
  // ...
}

CodePudding user response:

You may simply use list.get(i) to get the value:

List<Something> list = ...;
new IndexStream(list).forEach(i -> System.println("Index: "   i   ". Something: "   list.get(i)));

CodePudding user response:

The conceptual problem is, that one does not actually want a named subclass of Stream.

public class IndexedStreams {
    public static record IndexedValue<T>(int index, T value) { }

    private final AtomicInteger counter = new AtomicInteger; // For (stream).

    public static <T> Stream<IndexedValue> of(List<T> list) {
        return IntStream.range(0, list.size)
            .map(i -> new IndexedValue<T>(i, list.get(i));
    }

    public static <T> Stream<IndexedValue> of(Stream<T> stream) {
        return stream.map(v -> new IndexedValue<T>(counter.getAnIncrement(), v));
    }
}

Do not have a compiler at hand, so I am unsure about application of diamond <>. I am not sure whether java can do:

        return stream.map(v -> new IndexedValue(counter.getAnIncrement(), v) {
            private final AtomicInteger counter = new AtomicInteger;
        };
  • Related