質問

I wonder, if there's some stream operation that can do as each_with_index in ruby.

Where each_with_index iterates over the value as well as the index of the value.

役に立ちましたか?

解決

There is no stream operation specifically for that purpose. But you can mimic the functionality in several ways.

Index variable: The following approach works fine for sequential streams.

int[] index = { 0 };
stream.forEach(item -> System.out.printf("%s %d\n", item, index[0]++));

External iteration: The following approach works fine for parallel streams, as long as the original collection supports random access.

List<String> tokens = ...;
IntStream.range(0, tokens.size()).forEach(
    index -> System.out.printf("%s %d\n", tokens.get(index), index));

他のヒント

You can reduce it

<T> void forEachIndexed(Stream<T> stream, BiConsumer<Integer, T> consumer) {
    stream.reduce(0, (index, t) -> {
        consumer.accept(index, t);
        return index + 1;
    }, Integer::max);
}

this way:

List<Integer> ints = Arrays.asList(1, 2, 4, 6, 8, 16, 32);

forEachIndexed(ints.stream(), (idx, el) -> {
     System.out.println(idx + ": " + el);
});

You can use forEachWithIndex() in Eclipse Collections (formerly GS Collections).

MutableList<Integer> elements = FastList.newList();
IntArrayList indexes = new IntArrayList();
MutableList<Integer> collection = this.newWith(1, 2, 3, 4);
collection.forEachWithIndex((Integer object, int index) -> {
    elements.add(object);
    indexes.add(index);
});
Assert.assertEquals(FastList.newListWith(1, 2, 3, 4), elements);
Assert.assertEquals(IntArrayList.newListWith(0, 1, 2, 3), indexes);

If you cannot convert your Collection to a GS Collections type, you can use one of the adapters, like ListAdapter.

List<Integer> list = Arrays.asList(1, 2, 3, 4);
ListIterable<Integer> collection = ListAdapter.adapt(list);

collection.forEachWithIndex((object, index) -> {
    elements.add(object);
    indexes.add(index);
});

Note: I am a committer for Eclipse Collections.

Alternative with stream reduce operation with accumulator (2nd parameter) for side-effect. 3rd parameter could be any function, if you don't need the result from reduce operation.

 List<String> tokens = Arrays.asList("A", "B", "C", "D");
 tokens.stream().reduce(1, (i, str) -> {
        System.out.printf("%s %d\n", str, i);
        return i + 1;
    }, Integer::max);

PS: Although it is possible, I am personally not satisfied with abuse of reduce function. :)

Easy to do with utility library protonpack: https://github.com/poetix/protonpack

Stream<String> source = Stream.of("Foo", "Bar", "Baz");
List<Indexed<String>> zipped = StreamUtils.zipWithIndex(source).collect(Collectors.toList());
assertThat(zipped, contains(
    Indexed.index(0, "Foo"),
    Indexed.index(1, "Bar"),
    Indexed.index(2, "Baz")));
ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top