【问题标题】:Java 8 use streams to distinct objects with duplicated field valueJava 8 使用流来区分具有重复字段值的对象
【发布时间】:2018-12-03 15:19:51
【问题描述】:

我有一个对象列表。每个对象都有三个字段:idsecNumbertypeType 是枚举,它的值可以是 'new' 或 'legacy'。有时会发生该列表中的对象具有相同的secNumber a 但类型不同。

在这种情况下,我需要删除类型为“legacy”的那个。如何使用 Java 8 流来做到这一点?

【问题讨论】:

    标签: java filter java-8 java-stream


    【解决方案1】:

    toMap 用于类似这样的内容:

    Collection<T> result = list.stream()
        .collect(toMap(T::getSecNumber, 
                Function.identity(), 
                 (l, r) -> l.getType() == Type.LEGACY ? r : l))
        .values();
    

    其中T 是包含secNumberid 等的类。

    • keyMapper (T::getSecNumber) 从每个对象中提取每个 secNumber
    • valueMapper (Function.identity()) 将我们想要的对象提取为地图值,即来自它们自身的源中的对象。
    • mergeFunction(l, r) -&gt; 是我们所说的“如果两个给定对象具有相同的键,即getSecNumber,则保留其类型为 'NEW' 的那个并丢弃具有 'LEGACY' 的那个”,最后我们调用values() 将地图值累积到一个集合中。

    编辑:

    关注@Tomer Aberbach 的评论,您可能正在寻找:

    List<T> result = 
                list.stream()
                    .collect(groupingBy(T::getSecNumber))
                    .values()
                    .stream()
                    .flatMap(l -> l.stream().anyMatch(e -> e.getType() == Type.NEW) ?
                        l.stream().filter(e -> e.getType() != Type.LEGACY) :
                        l.stream())
                    .collect(toList());
    

    使用toMap 的第一个解决方案假定不能有多个对象具有相同的secNumbertype

    【讨论】:

    • 可能是因为它假设不能有多个对象具有相同的secNumber 和类型?因此,如果您有两个 NEW 类型的对象和相同的 secNumber,它将丢弃其中一个。
    • @TomerAberbach 真实,已编辑以适应您的评论。
    • @Aomine,我认为它并不完全存在,因为如果你有一堆只有 Type.LEGACY 类型的对象,而 secNumber 你会把它们全部扔掉。查看我的答案,了解我的意思。
    • @TomerAberbach 是的,我明白了,+1 顺便说一句,我将保留这两种解决方案,以防他们可能需要我说明的第一种方法。
    • 谢谢大家的回答。我使用了第二种方法,因为第一种方法返回错误,即 l 是没有 getType() 方法的 Object 类型。
    【解决方案2】:

    假设objects 是一个List&lt;ClassName&gt;,它已经被声明和初始化:

    List<ClassName> filteredObjects = objects.stream()
        .collect(Collectors.groupingBy(ClassName::getSecNumber))
        .values().stream()
        .flatMap(os -> os.stream().anyMatch(o -> o.getType() == Type.NEW) ?
            os.stream().filter(o -> o.getType() != Type.LEGACY) :
            os.stream()
        ).collect(Collectors.toList());
    

    我假设Type.LEGACY 类型的对象只有在存在另一个具有相同secNumberType.NEW 类型的对象时才应被过滤掉。我还假设您可以拥有多个相同 typesecNumber 的对象,并且可能需要保留这些对象。

    请注意,collect(Collectors.groupingBy(ClassName::getSecNumber)) 从任何类型的 secNumber 返回到 List&lt;ClassName&gt; 的映射,因此在其上调用 values() 返回一个 Collection&lt;List&lt;ClassName&gt;&gt;,它表示具有相同 secNumber 的对象分组的集合.

    flatMap部分通过secNumber获取每个分组,检查分组是否至少有一个Type.NEW的对象,如果有,则过滤掉Type.LEGACY类型的对象,否则只通过对象被展平成最终的List&lt;ClassName&gt;。这主要是为了如果一个分组只有Type.LEGACY 类型的对象,那么它们不会被排除在最终集合之外。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-07-25
      • 1970-01-01
      • 2021-05-22
      • 1970-01-01
      • 1970-01-01
      • 2020-05-16
      相关资源
      最近更新 更多