传递重复项的流操作

Stream operations passing on duplicates

我有这个逻辑,我根据供应商 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 列表

您的代码无效:

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

在您的情况下,您将接受在实体中找到其 vendorId 的所有供应商:anyMatch 将 returns true 如果 Predicate return s true 对于任何 T.

因此,导致您的问题。

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

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

noneMatch 将 return 为真,如果 Predicate 从不 return true 或者流为空。

您应该预先计算 vendorId:每次计算效率不高。

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());

只需在 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());