Java - 如何从集合中删除具有相同 属性 值的元素?

Java - how to delete elements with the same property value from collection?

假设有一个带有 SomeField 属性 的 SomeClass 元素集合。如何从此集合中删除具有等效 SomeField 属性的重复元素并仅保留一个具有该 SomeField 值的元素?

Java 集合有一个 optional remove 方法。假设您正在处理的集合支持它,您可以使用它:

boolean remove(Object o)

Removes a single instance of the specified element from this collection, if it is present (optional operation).

假设集合有一个 add 方法,你可以 运行 一个循环从集合中删除元素,当它存在时(使用 contains 检查),一旦它不存在有元素 add 它。

while(myCollection.contains(el)){
    myCollection.remove(el);
}
myCollection.add(el);

然后再一次 - 最好只从集合中创建一个 Set (例如通过将它传递给 TreeSet 构造函数) - 集合保证只有一个实例每个元素。

Set unique = new TreeSet(myCollection); // assumes comparable
Set unique2 = new HashSet(myCollection); // assumes hashCode

使用 Map

将所有内容转储到由 SomeField 键入的 Map 中(假设 SomeField 已明确定义 equalshashCode)然后取 Map.values .

如果要保留遇到的最后次重复:

final Collection<SomeClass> filtered = list.stream()
        .collect(Collectors.toMap(SomeClass::getKey, identity()))
        .values();

或者,如果您想要 第一个 重复反击:

final HashMap<Integer, SomeClass> mapped = list.stream()
        .collect(HashMap::new, (m, s) -> m.merge(s.getKey(), s, (l, r) -> l), HashMap::putAll);
final Collection<SomeClass> filtered = mapped.values();

在第二种情况下,类型推断系统需要一点帮助,所以你需要分配中间Map

Collections class 没有直接的 remove 方法。您可以实现 Collection 接口并实现 remove 方法,或者使用其他实现之一(LinkedList、Set、ArrayList 等);

以下为伪代码,您可以根据自己的需要进行改编:

Collection<YourType> list = new ArrayList<>();

// Add your objects to it - to make your collection
for (YourType T: ArrayOfYourType)
    list.add(T);

// Remove elements from the list

for (YourType T: list)
    if T.getSomeProps() == equals(your_val){  // Or equals()
        list.remove(T);
    }

您也可以使用地图对列出它们,但这对于您正在尝试做的事情来说可能有点矫枉过正。

您需要为 SomeClass 实现 hashCode 和 equals,以便仅考虑 SomeField。

class SomeClass {
  private SomeField field;
  public int hashCode() {
    return field.hashCode();
  }
  public boolean equals(Object o) {
    if (o instanceof SomeClass == false){
      return false
    }
    SomeClass someClass = (SomeClass)o;
    return someClass.field.equals(this.field)

  }
}

现在您可以将所有内容放入 Set 中以删除重复项

Set set = new HashSet(collection);

有几种简单的方法可以解决这个问题。

如果 SomeField 值是 SomeClass 的唯一成员,那么您可以根据 [=12] 轻松覆盖 SomeClass 中的 hashCodeequals =] 然后只需将您原来的 collection 添加到 HashSet.

如果不是这种情况并且 SomeClass 更复杂,您仍然可以使用 Set。但是,您需要以某种方式过滤掉重复项,一个好的方法是使用 ComparatorTreeSet

// Create a new Set with a specified comparator
final Collection<SomeClass> someClasses = 
        new TreeSet<>(Comparator.comparing(SomeClass::getSomeField));

// Add all elements from the original collection (duplicates will be removed)
someClasses.addAll(originalColl);

Comparator.comparing 方法创建一个 Comparator。如果你不使用 Java 8 a non-lambda Comparator 也可以使用:

Comparator<SomeClass> comparator = new Comparator<SomeClass>() {
    @Override
    public int compare(final SomeClass o1, final SomeClass o2) {
        // Do some kind of compare-operation. If SomeField is 
        // Comparable you can do it this way:
        return o1.getSomeField().compareTo(o2.getSomeField());
    }
}