首页 > 解决方案 > 如何根据字符串的组合删除重复项?

问题描述

我想比较getA(例如:123)和getB(例如:456)并找到重复的记录。

P1   getA           getB 
1    000123000      456      
P2   getA           getB 
2    000123001      456 

我在下面尝试过,但它会根据getA&getB组合找到重复项:

Map<Object, Boolean> findDuplicates = productsList.stream().collect(Collectors.toMap(cm -> Arrays.asList(cm.getB(),cm.getA().substring(3, cm.getCode().length() - 3)), cm -> false, (a, b) -> true));

现在我正在尝试删除cm.getA价值最低但无法在此处使用 comapartor 的记录:

productsList.removeIf(cm -> cm.getA() && findDuplicates .get(Arrays.asList(cm.getB(),cm.getA().substring(3, cm.getA().length() - 3))));

任何帮助,将不胜感激?

标签: javacollectionsjava-8

解决方案


您可以通过两个步骤来完成

Function<Product,Object> dupKey = cm ->
    Arrays.asList(cm.getB(), cm.getA().substring(3, cm.getA().length() - 3));

Map<Object, Boolean> duplicates = productsList.stream()
    .collect(Collectors.toMap(dupKey, cm -> false, (a, b) -> true));

Map<Object,Product> minDuplicates = productsList.stream()
    .filter(cm -> duplicates.get(dupKey.apply(cm)))
    .collect(Collectors.toMap(dupKey, Function.identity(),
        BinaryOperator.minBy(Comparator.comparing(Product::getA))));

productsList.removeAll(minDuplicates.values());

首先,它识别有重复的键,然后,它收集每个键的最小值,跳过没有重复的元素。最后,删除选定的值。

原则上,这可以一步完成,但是,它需要一个对象保存这两个信息,是否有特定键的重复项以及它们的最小值:

BinaryOperator<Product> min = BinaryOperator.minBy(Comparator.comparing(Product::getA));

Set<Product> minDuplicates = productsList.stream()
    .collect(Collectors.collectingAndThen(
        Collectors.toMap(dupKey, cm -> Map.entry(false,cm),
            (a, b) -> Map.entry(true, min.apply(a.getValue(), b.getValue()))),
        m -> m.values().stream().filter(Map.Entry::getKey)
              .map(Map.Entry::getValue).collect(Collectors.toSet())));

productsList.removeAll(minDuplicates);

这使用Map.Entry实例来保存两个不同类型的值。为了保持代码的可读性,它使用 Java 9 的Map.entry(K,V)工厂方法。当需要支持 Java 8 时,建议创建自己的工厂方法以保持代码简单:

static <K, V> Map.Entry<K, V> entry(K k, V v) {
    return new AbstractMap.SimpleImmutableEntry<>(k, v);
}

然后使用该方法而不是Map.entry.

逻辑与第一个变体中的逻辑相同,它将值映射到false元素本身并将它们合并到true最小元素,但现在一次完成。过滤必须在之后进行,以跳过false元素,然后映射到最小元素并将它们收集到一个Set.

然后,使用removeAll是一样的。


推荐阅读