如何在Java中根据某些属性合并两个不重复的流?

问题描述 投票:0回答:4

假设我们有如下两个流:

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
相同,我们就认为他们是同一个学生。 (所以 May 和 Marry 是同一个人,因为他们的数字都是“1”)。

我找到了

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

java java-8 java-stream
4个回答
27
投票

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

您的另一个问题是“如何合并两个

Stream<T>
而不覆盖
equals()
hashCode()
方法?”可以使用
toMap
收集器来完成,即 假设您不希望结果为
Stream<T>
。 示例:

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

如果您希望结果为

Stream<T>
那么可以这样做:

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

这可能没有那么高效,但它是返回

Stream<T>
的另一种方式,其中
T
项都是不同的,但不使用覆盖
equals
hashcode
,正如您所提到的。


17
投票

您可以使用

concat()

IntStream.concat(stream1, stream2)

3
投票

第一个问题 你可以使用“flatMap”

    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
方法获得所有不同元素的流。


0
投票

这是使用

StreamEx
库的解决方案:

Stream<Student> merged =
        StreamEx.of(stream1).append(stream2).distinct(Student::getNo)

这使用 StreamEx

append
方法来连接两个流。然后,它使用
distinct
方法的 StreamEx 变体,该方法使用函数来确定两个元素是否被视为相等:

public S distinct​(Function<? super T,​?> keyExtractor)

返回一个由该流的不同元素组成的流(根据应用给定函数的结果的对象相等性)。

© www.soinside.com 2019 - 2024. All rights reserved.