【问题标题】:Java - How to Remove Duplicates in ArrayList Based on Multiple Properties [duplicate]Java - 如何根据多个属性删除 ArrayList 中的重复项 [重复]
【发布时间】:2019-11-21 17:23:12
【问题描述】:

我想从基于多个属性的数组列表中删除重复记录。这是一个示例域对象类:

private String mdl;
private String ndc;
private String gpi;
private String labelName;
private int seqNo;
private String vendorName;

mdl、ndc、gpi 和 seqNo 共同构成一个唯一记录。我想在检查这 4 个属性的数组列表中查找重复项,然后如果列表中已存在具有相同 4 个属性的记录,则从列表中删除该记录。

【问题讨论】:

  • 自定义 hashcode 和 equals 方法,然后将对象存储到 Set 中
  • 你能举个例子吗?我已经覆盖了 hashcode 和 equals 方法,但是我将如何实现它以仅检查这些特定属性?
  • 从可扩展性的角度来看,我想知道提问者是否真的想要equals&hashCode,或者拥有一个自定义比较器和一个由它支持的集合就足够了。这样,“id-equivalence”可以远离所有字段 equals(这在应用程序的其他部分可能是必要的)。
  • 如果您发布覆盖的 equals 和 hashcode 方法的代码也会有所帮助。
  • 根据 OP 选择的答案,我认为这不是 stackoverflow.com/questions/2265503/… 的副本。似乎他们想要一种不使用 equals() 和 hashCode() 进行比较的方法

标签: java arrays list arraylist comparator


【解决方案1】:

.equals().hashCode() 应该被覆盖以说明您的密钥:mdl,ndc。 gpi,序列号这个网站上有无数的指南,但类似:

@Override
public boolean equals(Object obj) {
    if(obj != null && obj instanceof MyClass) {
        MyClass o = (MyClass)obj;
        return mdl.equals(o.mdl) && ndc.equals(o.ndc) &&
          gpi.equals(o.gpi) && seqNo == o.seqNo;
    }
    return false;
}

@Override
public int hashCode() {
    return Objects.hash(mdl, ndc, gpi, seqNo);
}

如果担心的话,可能有更有效的方法来实现它们。

然后你可以将你的列表转换成一个集合:

Set<MyClass> set = new HashSet<>(list);

生成的 set 不会有任何重复项,您现在可以根据需要将列表替换为新值 list = new ArrayList&lt;&gt;(set);

如果要保持原始列表中项目的顺序,请实例化LinkedHashSet 而不是HashSet

与您的直接问题无关,如果您想首先避免重复,不妨考虑使用Set 而不是List。这将使您的代码更高效(没有重复项的内存使用量更少)并且无需事后搜索重复项。

【讨论】:

  • OP 没有指定他重写了那些方法来支持问题中这 4 个变量的唯一性逻辑,因此这是基于它的假设。
  • @buræquete 实际上,OP 确实在他的评论中指定了以下问题:“我已经覆盖了 hashcode 和 equals 方法”
  • 是的,但是您可以覆盖并包含一个不会将这 4 个变量作为唯一哈希值的逻辑,对吗?他可能包括其他领域?他没有具体说明他在那些方法中这样做,如果你在答案中包括如何做到这一点,也许那会没问题(“但是我将如何实现它以仅检查这些特定属性?")
  • @buræquete 我明白你在说什么。我解释“我将如何实现它以仅检查这些特定属性?”这意味着OP想知道如何根据equals和hashcode函数消除重复项,而不是如何正确实现equals和hashcode。我想这是模棱两可的。
  • 我认为这种方法不适合单个用例,除非对象的规则是一致的并且允许equals(和hashcode)始终用于这些属性 - 它不是“错”,但也不一定是“对”
【解决方案2】:

您可以尝试执行以下操作;

List<Obj> list = ...; // list contains multiple objects
Collection<Obj> nonDuplicateCollection = list.stream()
        .collect(Collectors.toMap(Obj::generateUniqueKey, Function.identity(), (a, b) -> a))
        .values();

(a, b) -&gt; a,表示当两个对象相同时,最终的地图将包含较早的对象,后一个将被丢弃,如果您喜欢后一个,可以更改此行为。

Obj 在哪里;

public static class Obj {

    private String mdl;
    private String ndc;
    private String gpi;
    private String labelName;
    private int seqNo;
    private String vendorName;

    // other getter/setters

    public String generateUniqueKey() {
        return mdl + ndc + gpi + seqNo;
    }
}

我宁愿做这样的事情,也不愿覆盖 hashCodeequals 方法,这在默认状态下的另一个逻辑中可能是必要的......另外明确显示你如何用适当的方式断言唯一性像generateUniqueKey 这样的方法比在某些hashCode 方法中隐藏逻辑在可读性和可维护性方面要好得多。

【讨论】:

  • 如果您出于某种原因不想覆盖 equals 和 hashCode ,您可以这样做,但 OP 已经实现了它们,鉴于“唯一记录”,这似乎是正确的做法问题中的定义。在这种情况下,将列表放入一个集合中会是一种更简单的方法。
猜你喜欢
  • 1970-01-01
  • 2011-01-26
  • 2012-08-25
  • 1970-01-01
  • 1970-01-01
  • 2018-05-29
  • 2021-07-21
  • 2021-11-23
  • 1970-01-01
相关资源
最近更新 更多