【问题标题】:Map first element of stream differently than rest映射流的第一个元素与休息不同
【发布时间】:2018-03-23 18:13:40
【问题描述】:

在 Java 的 Stream API 中有没有一种方法可以以不同的方式映射流的第一个元素?

此代码的等效项:

List<Bar> barList = new ArrayList<>();

for (int i=0; i<fooList.size(); i++) {
    Foo foo = fooList.get(i);
    Foo modifiedFoo = foo.getModifiedFoo();
    if (i == 0) {
        barList.add(new Bar(modifiedFoo, false));
    }else {
        barList.add(new Bar(modifiedFoo, true));
    }
}

Stream<Bar> = barList.stream();

注意:我已经有一个流设置,我希望在第一次映射后进行一些操作

fooList.stream()
        .map(Foo::getModifiedFoo)
        .(May be Some operation here to get different new Bar for first modifiedFoo)
        .map(modifiedFoo -> new Bar(modifiedFoo, true));

【问题讨论】:

    标签: java-8 java-stream


    【解决方案1】:

    我会得到第一个元素,从中创建一个Stream 并应用所需的映射。然后,我将取出列表的其余部分,从中创建一个流并应用不同的映射。然后concat 流。像这样的:

    Stream<Bar> first = Stream.of(fooList.get(0))
        .map(Foo::getModifiedFoo)
        .map(modifiedFoo -> new Bar(modifiedFoo, false));
    
    Stream<Bar> others = fooList.subList(1, fooList.size()).stream()
        .map(Foo::getModifiedFoo)
        .map(modifiedFoo -> new Bar(modifiedFoo, true));
    
    Stream<Bar> bars = Stream.concat(first, others).flatMap(s -> s);
    

    另一种方法:

    Stream<Bar> bars = IntStream.range(0, fooList.size())
        .mapToObj(i -> new Bar(fooList.get(i).getModifiedFoo(), i > 0));
    

    这种方式简洁,效果很好。

    【讨论】:

    • 我喜欢最后一种方法,它聪明、紧凑、整洁。不错!
    • 遗憾的是只适用于列表。我要开始直播。
    【解决方案2】:

    使用IntStream 遍历索引,然后使用 mapToObj 为该索引创建一个对象,最后收集到一个列表中:

    List<Bar> barList = IntStream.range(0, fooList.size())
                                 .mapToObj(i -> (i == 0 ? new Bar (fooList.get(i), false) : 
                                                          new Bar(fooList.get(i),true)))
                                 .collect(Collectors.toList());
    

    但更具可读性的是,在循环外处理第一个项目,并使用从 1 开始的 IntStream。

    这是一个使用简单列表的demo

    【讨论】:

      【解决方案3】:

      我可以提出两种方法,但我觉得你的方法更直。

      IntStream 如:

      List<Bar> barList = new ArrayList<>();
      IntStream.range(0, fooList.size())
               .forEach(i->{
                      if (i == 0) {
                          barList.add(new Bar(foo, false));
                      }else {
                          barList.add(new Bar(foo, true));
                      }
               }
      );
      

      这不是一个真正的函数式方法(forEach() 使用并且没有Collector),因为它维护了 List 的当前索引。

      作为替代方案,您可以使用更实用的方法,但我也没有发现它更直接:

      List<Bar> barList = IntStream.range(0, fooList.size())
                                   .mapToObj(i->{
                                          Foo foo = fooList.get(i);
                                          if (i == 0) {
                                              return new Bar(foo, false);
                                          }
                                          return new Bar(foo, true));                                     
                                   })
                                   .collect(Collectors.toList());
      

      【讨论】:

      • 问题是在需要的操作之前我已经有一张地图。 fooList.stream().map(FooUtility::getModifiedFoo)._Some operation here for first modifiedFoo to get new Bar_.map(modifiedFoo -&gt; new Bar(modifiedFoo, true));
      • 可以简化为:.mapToObj(i -&gt; new Bar (fooList.get(i), i != 0))
      【解决方案4】:

      虽然我认为接受的答案更好,但这是另一种方法。

          int[] counter = {-1};
      
          Stream<Bar> barListStream = fooList.stream().map(foo -> {
                counter[0]++;
                return new Bar(mfoo.getModifiedFoo(), counter[0]>0);
             }).collect(Collectors.toList()).stream();
      

      【讨论】:

        【解决方案5】:

        你可以有一个对象来持有一个标志,例如AtomicBoolean 或 AtomicInteger - 您可以在第一次或第 n 次迭代时重置(您需要像 AtomicInteger 或一些 Integer 持有人在第 n 次迭代时重置),例如以下代码使用 HashMap 作为持有者类 - 将打印流的第一行与其他行不同:

            Map<String, Boolean> firstTime = new HashMap<>(Map.of("firstTime", true)); // to make the map modifiable
            try (Stream<String> lines = Files.lines(Paths.get(filename), Charset.defaultCharset())) {
                lines.forEachOrdered(line -> System.out.println(firstTime.remove("firstTime") != null ? ("firstTime: " + line) : line));
            }
        

        【讨论】:

          猜你喜欢
          • 2017-08-24
          • 1970-01-01
          • 2021-11-23
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2011-11-15
          • 1970-01-01
          相关资源
          最近更新 更多