【问题标题】:Stream operations passing on duplicates传递重复项的流操作
【发布时间】:2021-11-30 09:01:04
【问题描述】:

我有这个逻辑,我根据供应商 ID 列表vendors 进行过滤。在迭代此流之前,集合中已经有 2 个项目与 vendors 列表中的供应商 ID 相同。但是,一旦列表被处理,重复项就不会被过滤,我会得到另外两个项目。

这是如下代码。否定条件的filter 有什么问题?

List<Vendor> nonConfiguredVendors = null;

if (entities.isEmpty()) {
    nonConfiguredVendors = vendors;
} else {
    nonConfiguredVendors = vendors.stream()
            .filter(vendor -> entities.stream()
                    .anyMatch(entity -> !vendor.getVendorId().equalsIgnoreCase(entity.getVendorId())))
            .peek(System.out::println)
            .collect(Collectors.toList());
}

编辑vendors 的 ID 从 FC_101FC_150entities 已经有 FC_133FC_140 再次添加到 nonConfiguredVendors 列表中

【问题讨论】:

  • 您希望删除这段代码的哪一部分?过滤器不会去重,它只是检查供应商 ID 是否与实体流中的任何内容不匹配。
  • 添加了进一步阐述的编辑
  • 你能写一个简单的示例输入和预期的输出吗?

标签: java lambda java-stream


【解决方案1】:

只需在 entities 集合中创建一组唯一的供应商 ID,然后使用此集合过滤供应商

Set<String> uniqueIds = entities.stream()
                        .map(Entity::getVendorId)
                        .map(String::toLowerCase)
                        .collect(Collectors.toSet());

nonConfiguredVendors = vendors.stream()
                .filter(vendor -> !uniqueIds.contains(vendor.getVendorId().toLowerCase()))
                .peek(System.out::println)
                .collect(Collectors.toList());

【讨论】:

    【解决方案2】:

    您的代码无效:

    nonConfiguredVendors = vendors.stream()
                .filter(vendor -> entities.stream()
                        .anyMatch(entity -> !vendor.getVendorId().equalsIgnoreCase(entity.getVendorId())))
                )
    

    在您的情况下,您接受在实体中找到 vendorId 的所有供应商:如果 Predicate 为任何 T 返回 trueanyMatch 将返回 true

    因此,导致您的问题。

    正确的用例(但不是)应该是:

    nonConfiguredVendors = vendors.stream()
                .filter(vendor -> entities.stream()
                        .noneMatch(entity -> !vendor.getVendorId().equalsIgnoreCase(entity.getVendorId())))
                )
    

    如果Predicate 永远不会返回true 或流为空,noneMatch 将返回 true。

    你应该预先计算 vendorIds:每次计算它效率不高。

    var vendorIds = entities.stream()
                            .map(e -> e.getVendorId())
                            .collect(toCollection(() -> new TreeSet<String>());
    

    然后过滤:

    var nonConfiguredVendors = vendors.stream()
                                      .filter(vendor -> !vendorIds.contains(vendor.getVendorId()))
                .peek(System.out::println)
                .collect(Collectors.toList());
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-07-25
      • 1970-01-01
      • 2017-07-15
      • 2016-12-27
      相关资源
      最近更新 更多