在Java8中,有没有一种简洁的方法可以通过索引对流进行迭代?

在Java8中,有没有一种简洁的方法可以通过索引对流进行迭代?,java,java-8,java-stream,Java,Java 8,Java Stream,在访问流中的索引时,是否有一种简洁的方法来迭代流 String[] names = {"Sam","Pamela", "Dave", "Pascal", "Erik"}; List<String> nameList; Stream<Integer> indices = intRange(1, names.length).boxed(); nameList = zip(indices, stream(names), SimpleEntry::new) .f

在访问流中的索引时,是否有一种简洁的方法来迭代流

String[] names = {"Sam","Pamela", "Dave", "Pascal", "Erik"};

List<String> nameList;
Stream<Integer> indices = intRange(1, names.length).boxed();
nameList = zip(indices, stream(names), SimpleEntry::new)
        .filter(e -> e.getValue().length() <= e.getKey())
        .map(Entry::getValue)
        .collect(toList());
String[]name={“Sam”、“Pamela”、“Dave”、“Pascal”、“Erik”};
名单名单;
流索引=内部消息(1,names.length).boxed();
nameList=zip(索引、流(名称)、SimpleEntry::new)

.filter(e->e.getValue().length()c.length在访问索引时,没有方法在
上进行迭代,因为
不同于任何
集合
只是一个将数据从一个地方传输到另一个地方的管道,如下所述:

无存储。流不是存储元素的数据结构;相反,它们通过计算操作管道携带来自源(可能是数据结构、生成器、IO通道等)的值。


当然,正如您在问题中所暗示的那样,您始终可以将
转换为
集合
,例如
列表
,您可以在其中访问索引。

最干净的方法是从索引流开始:

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());

请注意,在并行流上使用后一种方法可能会中断,因为项目不必“按顺序”处理。

Java 8 streams API缺少获取流元素索引的功能以及将流压缩在一起的能力。这是不幸的,因为它使某些应用程序(像LINQ挑战)比其他挑战更困难

但是,通常会有解决办法。通常可以通过使用整数范围“驱动”流,并利用原始元素通常位于数组或索引可访问的集合中这一事实来实现。例如,挑战2问题可以通过以下方式解决:

String[] names = {"Sam", "Pamela", "Dave", "Pascal", "Erik"};

List<String> nameList =
    IntStream.range(0, names.length)
        .filter(i -> names[i].length() <= i)
        .mapToObj(i -> names[i])
        .collect(toList());
String[]name={“Sam”、“Pamela”、“Dave”、“Pascal”、“Erik”};
名单=
IntStream.range(0,names.length)
.filter(i->names[i].length()名称[i])
.collect(toList());
正如我前面提到的,这利用了数据源(名称数组)是可直接索引的这一事实

我承认这并不能满足挑战2的意图。尽管如此,它还是合理有效地解决了问题

编辑


我以前的代码示例使用
flatMap
来融合过滤器和映射操作,但这很麻烦,也没有任何优势。我已经根据Holger的评论更新了示例。

我在项目中使用了以下解决方案。我认为这比使用可变对象或整数范围要好

import java.util.*;
import java.util.function.*;
import java.util.stream.Collector;
import java.util.stream.Collector.Characteristics;
import java.util.stream.Stream;
import java.util.stream.StreamSupport;
import static java.util.Objects.requireNonNull;


public class CollectionUtils {
    private CollectionUtils() { }

    /**
     * Converts an {@link java.util.Iterator} to {@link java.util.stream.Stream}.
     */
    public static <T> Stream<T> iterate(Iterator<? extends T> iterator) {
        int characteristics = Spliterator.ORDERED | Spliterator.IMMUTABLE;
        return StreamSupport.stream(Spliterators.spliteratorUnknownSize(iterator, characteristics), false);
    }

    /**
     * Zips the specified stream with its indices.
     */
    public static <T> Stream<Map.Entry<Integer, T>> zipWithIndex(Stream<? extends T> stream) {
        return iterate(new Iterator<Map.Entry<Integer, T>>() {
            private final Iterator<? extends T> streamIterator = stream.iterator();
            private int index = 0;

            @Override
            public boolean hasNext() {
                return streamIterator.hasNext();
            }

            @Override
            public Map.Entry<Integer, T> next() {
                return new AbstractMap.SimpleImmutableEntry<>(index++, streamIterator.next());
            }
        });
    }

    /**
     * Returns a stream consisting of the results of applying the given two-arguments function to the elements of this stream.
     * The first argument of the function is the element index and the second one - the element value. 
     */
    public static <T, R> Stream<R> mapWithIndex(Stream<? extends T> stream, BiFunction<Integer, ? super T, ? extends R> mapper) {
        return zipWithIndex(stream).map(entry -> mapper.apply(entry.getKey(), entry.getValue()));
    }

    public static void main(String[] args) {
        String[] names = {"Sam", "Pamela", "Dave", "Pascal", "Erik"};

        System.out.println("Test zipWithIndex");
        zipWithIndex(Arrays.stream(names)).forEach(entry -> System.out.println(entry));

        System.out.println();
        System.out.println("Test mapWithIndex");
        mapWithIndex(Arrays.stream(names), (Integer index, String name) -> index+"="+name).forEach((String s) -> System.out.println(s));
    }
}
import java.util.*;
导入java.util.function.*;
导入java.util.stream.Collector;
导入java.util.stream.Collector.Characteristics;
导入java.util.stream.stream;
导入java.util.stream.StreamSupport;
导入静态java.util.Objects.requirennull;
公共类集合{
私有集合utils(){}
/**
*将{@link java.util.Iterator}转换为{@link java.util.stream.stream}。
*/
公共静态流迭代(迭代器With
你可以这样做:

String[] names = {"Sam","Pamela", "Dave", "Pascal", "Erik"};

List<String> nameList;
Stream<Integer> indices = IntStream.range(0, names.length).boxed(); 

nameList = StreamUtils.zip(indices, stream(names),SimpleEntry::new)
        .filter(e -> e.getValue().length() <= e.getKey()).map(Entry::getValue).collect(toList());                   

System.out.println(nameList);
String[]name={“Sam”、“Pamela”、“Dave”、“Pascal”、“Erik”};
名单名单;
流索引=IntStream.range(0,names.length).boxed();
nameList=StreamUtils.zip(索引、流(名称)、SimpleEntry::new)

.filter(e->e.getValue().length()除了protonpack之外,还提供了此功能(通过扩展构建在其上的库,我就是此库的作者)

Seq.Seq(名称流)).zipWithIndex()

.filter(namesWithIndex->namesWithIndex.v1.length()namesWithIndex.v1.length()为完整起见,以下是涉及我的库的解决方案:

String[]name={“Sam”、“Pamela”、“Dave”、“Pascal”、“Erik”};
EntryStream.of(名称)

.filterKeyValue((idx,str)->str.length()您可以创建一个静态内部类来封装索引器,正如我在下面的示例中所做的那样:

static class Indexer {
    int i = 0;
}

public static String getRegex() {
    EnumSet<MeasureUnit> range = EnumSet.allOf(MeasureUnit.class);
    StringBuilder sb = new StringBuilder();
    Indexer indexer = new Indexer();
    range.stream().forEach(
            measureUnit -> {
                sb.append(measureUnit.acronym);
                if (indexer.i < range.size() - 1)
                    sb.append("|");

                indexer.i++;
            }
    );
    return sb.toString();
}
静态类索引器{
int i=0;
}
公共静态字符串getRegex(){
EnumSet range=EnumSet.allOf(MeasureUnit.class);
StringBuilder sb=新的StringBuilder();
Indexer Indexer=新索引器();
range.stream().forEach(
测量单位->{
sb.追加(measureUnit.首字母缩写);
if(indexer.i
如果您不介意使用第三方库的话,它可以跨多种类型使用。下面是一组解决此问题的解决方案,用于JDK类型和Eclipse集合类型,使用
zipWithIndex

String[] names = { "Sam", "Pamela", "Dave", "Pascal", "Erik" };
ImmutableList<String> expected = Lists.immutable.with("Erik");
Predicate<Pair<String, Integer>> predicate =
    pair -> pair.getOne().length() <= pair.getTwo() + 1;

// JDK Types
List<String> strings1 = ArrayIterate.zipWithIndex(names)
    .collectIf(predicate, Pair::getOne);
Assert.assertEquals(expected, strings1);

List<String> list = Arrays.asList(names);
List<String> strings2 = ListAdapter.adapt(list)
    .zipWithIndex()
    .collectIf(predicate, Pair::getOne);
Assert.assertEquals(expected, strings2);

// Eclipse Collections types
MutableList<String> mutableNames = Lists.mutable.with(names);
MutableList<String> strings3 = mutableNames.zipWithIndex()
    .collectIf(predicate, Pair::getOne);
Assert.assertEquals(expected, strings3);

ImmutableList<String> immutableNames = Lists.immutable.with(names);
ImmutableList<String> strings4 = immutableNames.zipWithIndex()
    .collectIf(predicate, Pair::getOne);
Assert.assertEquals(expected, strings4);

MutableList<String> strings5 = mutableNames.asLazy()
    .zipWithIndex()
    .collectIf(predicate, Pair::getOne, Lists.mutable.empty());
Assert.assertEquals(expected, strings5);
如果您将lambda更改为上面的匿名内部类,那么所有这些代码示例也将在Java5-7中工作

注意:我是Eclipse集合的提交人

以下是代码

Stream.of(names.index)()

.filter(e->e.value().length(),带有一个可以尝试的列表

List<String> strings = new ArrayList<>(Arrays.asList("First", "Second", "Third", "Fourth", "Fifth")); // An example list of Strings
strings.stream() // Turn the list into a Stream
    .collect(HashMap::new, (h, o) -> h.put(h.size(), o), (h, o) -> {}) // Create a map of the index to the object
        .forEach((i, o) -> { // Now we can use a BiConsumer forEach!
            System.out.println(String.format("%d => %s", i, o));
        });

由于番石榴21,您可以使用

Streams.mapWithIndex()
示例(来自):

这个问题()已将当前问题标记为重复问题,因此我无法在那里回答它;我在这里回答它

下面是一个通用的解决方案,用于获取不需要外部库的匹配索引

如果你有一份清单

public static <T> int indexOf(List<T> items, Predicate<T> matches) {
        return IntStream.range(0, items.size())
                .filter(index -> matches.test(items.get(index)))
                .findFirst().orElse(-1);
}
如果使用集合,请尝试此集合

   public static <T> int indexOf(Collection<T> items, Predicate<T> matches) {
        int index = -1;
        Iterator<T> it = items.iterator();
        while (it.hasNext()) {
            index++;
            if (matches.test(it.next())) {
                return index;
            }
        }
        return -1;
    }
publicstaticintindexof(集合项、谓词匹配){
int指数=-1;
Iterator it=items.Iterator();
while(it.hasNext()){
索引++;
if(匹配.test(it.next())){
收益指数;
}
}
返回-1;
}
如果您碰巧使用Vavr(以前称为Javaslang),您可以利用专用方法:

Stream.of("A", "B", "C")
  .zipWithIndex();

MutableList<String> mutableNames = Lists.mutable.with("Sam", "Pamela", "Dave", "Pascal", "Erik"); ImmutableList<String> expected = Lists.immutable.with("Erik"); List<String> actual = Lists.mutable.empty(); mutableNames.forEachWithIndex((name, index) -> { if (name.length() <= index + 1) actual.add(name); }); Assert.assertEquals(expected, actual);

Stream.of(names).indexed()
      .filter(e -> e.value().length() <= e.index())
      .map(Indexed::value).toList();
List<String> strings = new ArrayList<>(Arrays.asList("First", "Second", "Third", "Fourth", "Fifth")); // An example list of Strings
strings.stream() // Turn the list into a Stream
    .collect(HashMap::new, (h, o) -> h.put(h.size(), o), (h, o) -> {}) // Create a map of the index to the object
        .forEach((i, o) -> { // Now we can use a BiConsumer forEach!
            System.out.println(String.format("%d => %s", i, o));
        });
0 => First
1 => Second
2 => Third
3 => Fourth
4 => Fifth
Streams.mapWithIndex()
Streams.mapWithIndex(
    Stream.of("a", "b", "c"),
    (str, index) -> str + ":" + index)
) // will return Stream.of("a:0", "b:1", "c:2")
public static <T> int indexOf(List<T> items, Predicate<T> matches) {
        return IntStream.range(0, items.size())
                .filter(index -> matches.test(items.get(index)))
                .findFirst().orElse(-1);
}
int index = indexOf(myList, item->item.getId()==100);
   public static <T> int indexOf(Collection<T> items, Predicate<T> matches) {
        int index = -1;
        Iterator<T> it = items.iterator();
        while (it.hasNext()) {
            index++;
            if (matches.test(it.next())) {
                return index;
            }
        }
        return -1;
    }
Stream.of("A", "B", "C")
  .zipWithIndex();
Stream((A, 0), ?)
public class WithIndex<T> {
    private int index;
    private T value;

    WithIndex(int index, T value) {
        this.index = index;
        this.value = value;
    }

    public int index() {
        return index;
    }

    public T value() {
        return value;
    }

    @Override
    public String toString() {
        return value + "(" + index + ")";
    }

    public static <T> Function<T, WithIndex<T>> indexed() {
        return new Function<T, WithIndex<T>>() {
            int index = 0;
            @Override
            public WithIndex<T> apply(T t) {
                return new WithIndex<>(index++, t);
            }
        };
    }
}
public static void main(String[] args) {
    Stream<String> stream = Stream.of("a", "b", "c", "d", "e");
    stream.map(WithIndex.indexed()).forEachOrdered(e -> {
        System.out.println(e.index() + " -> " + e.value());
    });
}
AtomicInteger index = new AtomicInteger();
Stream.of(names)
  .map(e->new Object() { String n=e; public i=index.getAndIncrement(); })
  .filter(o->o.n.length()<=o.i) // or do whatever you want with pairs...
  .forEach(o->System.out.println("idx:"+o.i+" nam:"+o.n));
OptionalInt index = IntStream.range(0, list.size())
    .filter(i -> list.get(i) == 3)
    .findFirst();
IntStream.range(0, list.size())
   .filter(i -> list.get(i) == 3)
   .collect(Collectors.toList());
String[] names = {"Sam","Pamela", "Dave", "Pascal", "Erik"};
List<String> nameList = IntStream.iterate(0, i -> i < names.length, i -> i + 1)
        .filter(i -> names[i].length() <= i)
        .mapToObj(i -> names[i])
        .collect(Collectors.toList());
String[] names = {"Sam","Pamela", "Dave", "Pascal", "Erik"};
List<String> nameList = IntStream.iterate(0, i -> i + 1)
        .limit(names.length)
        .filter(i -> names[i].length() <= i)
        .mapToObj(i -> names[i])
        .collect(Collectors.toList());
String[] namesArray = {"Sam","Pamela", "Dave", "Pascal", "Erik"};
String completeString
         =  IntStream.range(0,namesArray.length)
           .mapToObj(i -> namesArray[i]) // Converting each array element into Object
           .map(String::valueOf) // Converting object to String again
           .collect(Collectors.joining(",")); // getting a Concat String of all values
        System.out.println(completeString);
String[] namesArray = {"Sam","Pamela", "Dave", "Pascal", "Erik"};

IntStream.range(0,namesArray.length)
               .mapToObj(i -> namesArray[i]) // Converting each array element into Object
               .map(String::valueOf) // Converting object to String again
               .forEach(s -> {
                //You can do various operation on each element here
                System.out.println(s);
               }); // getting a Concat String of all 
String[] namesArray = {"Sam","Pamela", "Dave", "Pascal", "Erik"};
 List<String> namesList
                =  IntStream.range(0,namesArray.length)
                .mapToObj(i -> namesArray[i]) // Converting each array element into Object
                .map(String::valueOf) // Converting object to String again
                .collect(Collectors.toList()); // collecting elements in List
        System.out.println(listWithIndex);
int[] idx = new int[] { 0 };
Stream.of(names)
    .filter(name -> name.length() <= idx[0]++)
    .collect(Collectors.toList());
  public class IndexedValue {

    private final int    index;
    private final Object value;

    public IndexedValue(final int index, final Object value) { 
        this.index = index;
        this.value = value;
    }

    public int getIndex() {
        return index;
    }

    public Object getValue() {
        return value;
    }
}
@Test
public void withIndex() {
    final List<String> list = Arrays.asList("a", "b");
    IntStream.range(0, list.size())
             .mapToObj(index -> new IndexedValue(index, list.get(index)))
             .forEach(indexValue -> {
                 System.out.println(String.format("%d, %s",
                                                  indexValue.getIndex(),
                                                  indexValue.getValue().toString()));
             });
}