【问题标题】:How to map elements of the list to their indices using Java 8 streams?如何使用 Java 8 流将列表的元素映射到它们的索引?
【发布时间】:2015-03-11 14:51:08
【问题描述】:

有一个字符串列表,我需要构造一个对象列表,它们实际上是对(string, its position in the list)。目前我有这样的代码使用谷歌收藏:

public Robots(List<String> names) {
    ImmutableList.Builder<Robot> builder = ImmutableList.builder();
    for (int i = 0; i < names.size(); i++) {
        builder.add(new Robot(i, names.get(i)));
    }
    this.list = builder.build();
}

我想使用 Java 8 流来执行此操作。如果没有索引,我可以这样做:

public Robots(List<String> names) {
    this.list = names.stream()
            .map(Robot::new) // no index here
            .collect(collectingAndThen(
                    Collectors.toList(),
                    Collections::unmodifiableList
            ));
}

要获得索引,我必须这样做:

public Robots(List<String> names) {
    AtomicInteger integer = new AtomicInteger(0);
    this.list = names.stream()
            .map(string -> new Robot(integer.getAndIncrement(), string))
            .collect(collectingAndThen(
                    Collectors.toList(),
                    Collections::unmodifiableList
            ));
}

但是,文档说映射函数应该是无状态的,但 AtomicInteger 实际上是它的状态。

有没有办法将顺序流的元素映射到它们在流中的位置?

【问题讨论】:

    标签: java lambda java-8 java-stream


    【解决方案1】:

    你可以这样做:

    public Robots(List<String> names) {
        this.list = IntStream.range(0, names.size())
                             .mapToObj(i -> new Robot(i, names.get(i)))
                             .collect(collectingAndThen(toList(), Collections::unmodifiableList));
    }
    

    但是,根据列表的底层实现,它可能效率不高。您可以从 IntStream 获取迭代器;然后在mapToObj 中调用next()

    作为替代方案,proton-pack 库为流定义了zipWithIndex 功能:

     this.list = StreamUtils.zipWithIndex(names.stream())
                            .map(i -> new Robot(i.getIndex(), i.getValue()))
                            .collect(collectingAndThen(toList(), Collections::unmodifiableList));
    

    【讨论】:

    • 如果我在映射函数中使用来自Iteratornext(),它将是有状态的。 zipWithIndex 看起来很有趣 - 它不直接使用列表,因此它可以与任何流一起使用。谢谢!
    • @JaroslawPawlak 是的,这是真的。是的,例如,如果基础列表是LinkedList;你会得到糟糕的表现。 zipWithIndex 返回一个带有 Long 索引的 Stream;如果你真的需要Integer,你可以通过提供一个(可能)无限的IntStream :-) 来使用 zip 方法
    【解决方案2】:

    最简单的方法是流式索引:

    List<Robot> robots = IntStream.range(0, names.size())
                                  .mapToObj(i -> new Robot(i, names.get(i))
                                  .collect(toList());
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2018-03-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-09-01
      • 2015-12-27
      • 2022-12-18
      • 2019-05-17
      相关资源
      最近更新 更多