如何根据字符串的组合删除重复项?

时间:2019-07-26 07:42:26

标签: java collections java-8

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

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

我在下面尝试过,但是它根据getAgetB的组合找到重复项:

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

有什么帮助吗?

3 个答案:

答案 0 :(得分:0)

您可以将字符串设为数组列表,然后遍历数组列表,然后将其与其他数组列表进行比较。

答案 1 :(得分:0)

您可以通过两个步骤完成

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是相同的。

答案 2 :(得分:0)

您可以使用重复键和TreeSet的映射,而不是将重复键映射为boolean。这将使其一步之遥。就像在TreeSet中一样,元素始终保持排序状态,您无需在下一步中对其进行排序即可找到最小值。

public class ProductDups {

    public static void main(String[] args) {

        List<Product> productsList = new ArrayList<>();
        productsList.add(new Product("000123000", "456"));
        productsList.add(new Product("000123001", "456"));
        productsList.add(new Product("000124003", "567"));
        productsList.add(new Product("000124002", "567"));

        List<Product> minDuplicates = productsList.stream()
                .collect(
                        Collectors.toMap(
                                p -> Arrays.asList(p.getB(),
                                        p.getA().substring(3, p.getA().length() - 3)),
                                p -> {
                                    TreeSet<Product> ts = new TreeSet<>(Comparator.comparing(Product::getA));
                                    ts.addAll(Arrays.asList(p));
                                    return ts;
                                },
                                (a, b) -> {
                                    a.addAll(b);
                                    return a;
                                }
                        )
                )
                .entrySet()
                .stream()
                .filter(e -> e.getValue().size() > 1)
                .map(e -> e.getValue().first())
                .collect(Collectors.toList());
        System.out.println(minDuplicates);

    }
}
class Product {

    String a;
    String b;

    public Product(String a, String b) {
        this.a = a;
        this.b = b;
    }

    public String getA() {
        return a;
    }

    public void setA(String a) {
        this.a = a;
    }

    public String getB() {
        return b;
    }

    public void setB(String b) {
        this.b = b;
    }

    @Override
    public String toString() {
        return "Product{" +
                "a='" + a + '\'' +
                ", b='" + b + '\'' +
                '}';
    }
}