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

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

与这里给出的LINQ示例相比,这似乎相当令人失望

string[] names = { "Sam", "Pamela", "Dave", "Pascal", "Erik" };
var nameList = names.Where((c, index) => c.Length <= index + 1).ToList();

有更简洁的方式吗?

此外,似乎拉链已经移动或被拆除…


当前回答

除了protonpack之外,jOOλ的Seq也提供了这种功能(通过在其上构建的扩展库,如cyclops-react,我是这个库的作者)。

Seq.seq(Stream.of(names)).zipWithIndex()
                         .filter( namesWithIndex -> namesWithIndex.v1.length() <= namesWithIndex.v2 + 1)
                         .toList();

Seq还只支持Seq.of(names),并将在幕后构建一个JDK流。

简单反应的等效物看起来类似

 LazyFutureStream.of(names)
                 .zipWithIndex()
                 .filter( namesWithIndex -> namesWithIndex.v1.length() <= namesWithIndex.v2 + 1)
                 .toList();

简单反应版本更适合异步/并发处理。

其他回答

正如jean-baptiste-yunès所说,如果您的流是基于java列表的,那么使用AtomicInteger及其incrementAndGet方法是一个很好的解决问题的方法,并且返回的整数与原始列表中的索引对应,只要您不使用并行流。

除了protonpack之外,jOOλ的Seq也提供了这种功能(通过在其上构建的扩展库,如cyclops-react,我是这个库的作者)。

Seq.seq(Stream.of(names)).zipWithIndex()
                         .filter( namesWithIndex -> namesWithIndex.v1.length() <= namesWithIndex.v2 + 1)
                         .toList();

Seq还只支持Seq.of(names),并将在幕后构建一个JDK流。

简单反应的等效物看起来类似

 LazyFutureStream.of(names)
                 .zipWithIndex()
                 .filter( namesWithIndex -> namesWithIndex.v1.length() <= namesWithIndex.v2 + 1)
                 .toList();

简单反应版本更适合异步/并发处理。

一种可能的方法是索引流中的每个元素:

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

在流中使用匿名类虽然非常有用,但却没有得到很好的使用。

你不一定需要地图 这是最接近LINQ示例的lambda:

int[] idx = new int[] { 0 };
Stream.of(names)
    .filter(name -> name.length() <= idx[0]++)
    .collect(Collectors.toList());

如果您需要forEach中的索引,那么这提供了一种方法。

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