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
已明确定义 equals
和 hashCode
)然后取 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
中的 hashCode
和 equals
=] 然后只需将您原来的 collection 添加到 HashSet
.
如果不是这种情况并且 SomeClass
更复杂,您仍然可以使用 Set
。但是,您需要以某种方式过滤掉重复项,一个好的方法是使用 Comparator
和 TreeSet
。
// 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());
}
}
假设有一个带有 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
已明确定义 equals
和 hashCode
)然后取 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
中的 hashCode
和 equals
=] 然后只需将您原来的 collection 添加到 HashSet
.
如果不是这种情况并且 SomeClass
更复杂,您仍然可以使用 Set
。但是,您需要以某种方式过滤掉重复项,一个好的方法是使用 Comparator
和 TreeSet
。
// 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());
}
}