Java 8 Streams FlatMap方法示例

chi*_*tiz 84 java java-8 java-stream flatmap

我一直在检查即将到来的Java update,即:Java 8 or JDK 8.是的,我很不耐烦,有很多新东西,但是,有一些我不明白的东西,一些简单的代码:

final Stream<Integer>stream = Stream.of(1,2,3,4,5,6,7,8,9,10);
stream.flatMap();
Run Code Online (Sandbox Code Playgroud)

javadoc是

public <R> Stream<R> flatMap(Function<? super T,? extends Stream<? extends R>> mapper)

返回一个流,该流包含将此流的每个元素替换为通过将提供的映射函数应用于每个元素而生成的映射流的内容的结果.每个映射的流在其内容放入此流后关闭.(如果映射的流为空,则使用空流.)这是一个中间操作.

如果有人创建了一些简单的现实生活示例flatMap,如何在以前的java版本Java[6,7]中编写代码以及如何使用相同的例程编写代码,我将不胜感激Java 8.

Nic*_*olt 157

对于已经持平flatMapStream来说没有意义,就像Stream<Integer>你在问题中所显示的那样.

但是,如果你有一个Stream<List<Integer>>那么它会有意义,你可以这样做:

Stream<List<Integer>> integerListStream = Stream.of(
    Arrays.asList(1, 2), 
    Arrays.asList(3, 4), 
    Arrays.asList(5)
);

Stream<Integer> integerStream = integerListStream .flatMap(Collection::stream);
integerStream.forEach(System.out::println);
Run Code Online (Sandbox Code Playgroud)

哪个会打印:

1
2
3
4
5
Run Code Online (Sandbox Code Playgroud)

要在Java 8之前执行此操作,您只需要一个循环:

List<List<Integer>> integerLists = Arrays.asList(
    Arrays.asList(1, 2), 
    Arrays.asList(3, 4), 
    Arrays.asList(5)
)

List<Integer> flattened = new ArrayList<>();

for (List<Integer> integerList : integerLists) {
    flattened.addAll(integerList);
}

for (Integer i : flattened) {
    System.out.println(i);
}
Run Code Online (Sandbox Code Playgroud)


ass*_*ias 113

举个例子

想象一下,你想要创建以下序列:1,2,3,3,3,4,4,4,4等(换句话说:1x1,2x2,3x3等)

有了flatMap它可能看起来像:

IntStream sequence = IntStream.rangeClosed(1, 4)
                          .flatMap(i -> IntStream.iterate(i, identity()).limit(i));
sequence.forEach(System.out::println);
Run Code Online (Sandbox Code Playgroud)

哪里:

  • IntStream.rangeClosed(1, 4)创建一个int从1到4 的流,包括1和4
  • IntStream.iterate(i, identity()).limit(i)创建一个i的长度为inti 的流- 因此应用于i = 4它会创建一个流:4, 4, 4, 4
  • flatMap "压扁"流并将其"连接"到原始流

使用Java <8,您将需要两个嵌套循环:

List<Integer> list = new ArrayList<>();
for (int i = 1; i <= 4; i++) {
    for (int j = 0; j < i; j++) {
        list.add(i);
    }
}
Run Code Online (Sandbox Code Playgroud)

现实世界的例子

假设我的List<TimeSeries>每个TimeSeries基本上都是一个Map<LocalDate, Double>.我想获得至少有一个时间序列具有值的所有日期的列表.flatMap救援:

list.stream().parallel()
    .flatMap(ts -> ts.dates().stream()) // for each TS, stream dates and flatmap
    .distinct()                         // remove duplicates
    .sorted()                           // sort ascending
    .collect(toList());
Run Code Online (Sandbox Code Playgroud)

它不仅可读,而且如果您突然需要处理100k元素,只需添加parallel()即可在不编写任何并发代码的情况下提高性能.

  • 这两个例子都比接受的答案要好得多. (14认同)
  • `import static java.util.function.Function.identity;` (4认同)
  • @ user3320018你需要静态导入`Function.identity`. (2认同)

小智 18

从短语列表中提取排序ASC的唯一单词:

List<String> phrases = Arrays.asList(
        "sporadic perjury",
        "confounded skimming",
        "incumbent jailer",
        "confounded jailer");

List<String> uniqueWords = phrases
        .stream()
        .flatMap(phrase -> Stream.of(phrase.split(" +")))
        .distinct()
        .sorted()
        .collect(Collectors.toList());
System.out.println("Unique words: " + uniqueWords);
Run Code Online (Sandbox Code Playgroud)

......和输出:

Unique words: [confounded, incumbent, jailer, perjury, skimming, sporadic]
Run Code Online (Sandbox Code Playgroud)


Ale*_*ets 11

我是唯一一个发现无聊列表无聊的人吗?;-)

让我们试试对象吧.顺便说一下现实世界的例子.

给定:表示重复任务的对象.关于重要的任务栏:提醒开始响铃start并重复每一个repeatPeriod repeatUnit(例如5个小时)repeatCount,总共会有提醒(包括开始提醒).

目标:实现任务副本列表,每个任务提醒调用一个.

List<Task> tasks =
            Arrays.asList(
                    new Task(
                            false,//completed sign
                            "My important task",//task name (text)
                            LocalDateTime.now().plus(2, ChronoUnit.DAYS),//first reminder(start)
                            true,//is task repetitive?
                            1,//reminder interval
                            ChronoUnit.DAYS,//interval unit
                            5//total number of reminders
                    )
            );

tasks.stream().flatMap(
        x -> LongStream.iterate(
                x.getStart().toEpochSecond(ZoneOffset.UTC),
                p -> (p + x.getRepeatPeriod()*x.getRepeatUnit().getDuration().getSeconds())
        ).limit(x.getRepeatCount()).boxed()
        .map( y -> new Task(x,LocalDateTime.ofEpochSecond(y,0,ZoneOffset.UTC)))
).forEach(System.out::println);
Run Code Online (Sandbox Code Playgroud)

输出:

Task{completed=false, text='My important task', start=2014-10-01T21:35:24, repeat=false, repeatCount=0, repeatPeriod=0, repeatUnit=null}
Task{completed=false, text='My important task', start=2014-10-02T21:35:24, repeat=false, repeatCount=0, repeatPeriod=0, repeatUnit=null}
Task{completed=false, text='My important task', start=2014-10-03T21:35:24, repeat=false, repeatCount=0, repeatPeriod=0, repeatUnit=null}
Task{completed=false, text='My important task', start=2014-10-04T21:35:24, repeat=false, repeatCount=0, repeatPeriod=0, repeatUnit=null}
Task{completed=false, text='My important task', start=2014-10-05T21:35:24, repeat=false, repeatCount=0, repeatPeriod=0, repeatUnit=null}
Run Code Online (Sandbox Code Playgroud)

PS:如果有人提出更简单的解决方案,我会很感激,毕竟我不是职业选手.

更新: @RBz要求详细说明,所以在这里.基本上,flatMap将来自另一个流内的流的所有元素放入输出流中.这里有很多流:) 因此,对于初始流中的每个任务,lambda表达式x -> LongStream.iterate...创建一个表示任务开始时刻的长值流.此流仅限于x.getRepeatCount()实例.它的值从开始x.getStart().toEpochSecond(ZoneOffset.UTC),每个下一个值使用lambda计算p -> (p + x.getRepeatPeriod()*x.getRepeatUnit().getDuration().getSeconds().boxed()返回带有每个long值的流作为Long包装器实例.然后,该流中的每个Long都将映射到不再重复的新Task实例,并包含准确的执行时间.此示例在输入列表中只包含一个任务.但想象你有一千个.然后,您将拥有1000个Task对象流.flatMap这里有什么把所有流中的所有任务放到同一个输出流上.这就是我理解的一切.谢谢你的问题!

  • "我是唯一一个发现无聊名单无聊的人吗?"+1 (8认同)
  • 我发现很难理解这个例子.:( (2认同)