【问题标题】:How to merge two streams in Java?如何在 Java 中合并两个流?
【发布时间】:2019-03-05 13:58:37
【问题描述】:

假设我们有如下两个流:

IntStream stream1 = Arrays.stream(new int[] {13, 1, 3, 5, 7, 9});
IntStream stream2 = Arrays.stream(new int[] {1, 2, 6, 14, 8, 10, 12});
stream1.merge(stream2); // some method which is used to merge two streams.

是否有任何方便的方法可以使用 Java 8 流 API 将两个流合并到 [13, 1, 2, 3, 5, 6, 7, 8, 9, 10, 12, 14]没关系)。还是只能同时处理一个流?

此外,如果这两个流是对象流,怎么可能只保留不同的对象,而不覆盖equals()hashCode() 方法?例如:

public class Student {

    private String no;

    private String name;
}

Student s1 = new Student("1", "May");
Student s2 = new Student("2", "Bob");
Student s3 = new Student("1", "Marry");

Stream<Student> stream1 = Stream.of(s1, s2);
Stream<Student> stream2 = Stream.of(s2, s3);
stream1.merge(stream2);  // should return Student{no='1', name='May'} Student{no='2', name='Bob'}

当两个学生的no 相同且与name 无关时,我们将其视为相同(因此 May 和 Marry 是同一个人,因为他们的数字都是“1”)。

我找到了distinct() 方法,但是这个方法是基于Object#equals() 的。如果不允许覆盖equals() 方法,如何将stream1stream2 合并到一个没有重复项的流中?

【问题讨论】:

  • 你可以直接写IntStream.of(13, 1, etc),而不是Arrays.stream(new int[] {13, 1, 3, 5, 7, 9});

标签: java java-8 java-stream


【解决方案1】:

你可以使用concat()

IntStream.concat(stream1, stream2)

【讨论】:

  • 谢谢,它成功了。但是很遗憾contact()方法并没有为我们去除重复项,所以我们不得不多使用一个distinct()方法。
  • @weaver 为什么希望concat 删除重复项?
  • 为了删除重复项,您可以在连接后调用.distinct()
  • @weaver 这就是流的意义......流上的链式操作。
【解决方案2】:

@Jigar Joshi 回答了您问题的第一部分,即“如何将两个 IntStream 合并为一个”

您的另一个问题是“如何在不覆盖 equals()hashCode() 方法的情况下合并两个 Stream&lt;T&gt;?”可以使用toMap 收集器来完成,即 假设您不希望结果为Stream&lt;T&gt;。 示例:

Stream.concat(stream1, stream2)
      .collect(Collectors.toMap(Student::getNo, 
               Function.identity(), 
               (l, r) -> l, 
               LinkedHashMap::new)
      ).values();

如果您希望结果为Stream&lt;T&gt;,那么可以这样做:

 Stream.concat(stream1, stream2)
       .collect(Collectors.collectingAndThen(
               Collectors.toMap(Student::getNo,
                    Function.identity(),
                    (l, r) -> l,
                    LinkedHashMap::new), 
                    f -> f.values().stream()));

这可能效率不高,但它是返回Stream&lt;T&gt; 的另一种方式,其中T 项目都是不同的,但没有使用覆盖equalshashcode,正如你所提到的。

【讨论】:

    【解决方案3】:

    第一个问题 你可以使用“平面地图”

        IntStream stream1 = Arrays.stream(new int[] {13, 1, 3, 5, 7, 9});
        IntStream stream2 = Arrays.stream(new int[] {1, 2, 6, 14, 8, 10, 12});
    
        List<Integer> result = Stream.of(stream1, stream2).flatMap(IntStream::boxed)
                .collect(Collectors.toList());
        //result={13, 1, 3, 5, 7, 9, 1, 2, 6, 14, 8, 10, 12}
    

    编辑

    感谢@Vinicius 的建议, 我们可以使用

    Stream<Integer> result = Stream.of(stream1, stream2).flatMap(IntStream::boxed).distinct();
    

    在这里,我们将根据equals 方法获得所有不同元素的流。

    【讨论】:

    • 在 flatMap 后面放一个 distinct() 就更好了
    猜你喜欢
    • 2010-10-20
    • 2019-04-17
    • 1970-01-01
    • 2011-11-03
    • 2011-08-06
    • 2020-09-20
    • 2019-06-11
    • 2018-05-02
    • 2013-03-17
    相关资源
    最近更新 更多