正如 @LuiggiMendoza 在 cmets 中建议的那样:
您可以创建一个自定义的 Comparator 类来比较两个 Person 对象的相等性,忽略它们的 ID。
class PersonComparator implements Comparator<Person> {
// wraps the compareTo method to compare two Strings but also accounts for NPE
int compareStrings(String a, String b) {
if(a == b) { // both strings are the same string or are null
return 0;
} else if(a == null) { // first string is null, result is negative
return -1;
} else if(b == null){ // second string is null, result is positive
return 1;
} else { // no strings are null, return the result of compareTo
return a.compareTo(b);
}
}
@Override
public int compare(Person p1, Person p2) {
// comparisons on Person objects themselves
if(p1 == p2) { // Person 1 and Person 2 are the same Person object
return 0;
}
if(p1 == null && p2 != null) { // Person 1 is null and Person 2 is not, result is negative
return -1;
}
if(p1 != null && p2 == null) { // Person 1 is not null and Person 2 is, result is positive
return 1;
}
int result = 0;
// comparisons on the attributes of the Persons objects
result = compareStrings(p1.firstname, p2.firstname);
if(result != 0) { // Persons differ in first names, we can return the result
return result;
}
result = compareStrings(p1.lastname, p2.lastname);
if(result != 0) { // Persons differ in last names, we can return the result
return result;
}
return Integer.compare(p1.age, p2.age); // if both first name and last names are equal, the comparison difference is in their age
}
}
现在您可以将TreeSet 结构与此自定义Comparator 一起使用,例如,创建一个消除重复值的简单方法。
List<Person> getListWithoutDups(List<Person> list) {
List<Person> newList = new ArrayList<Person>();
TreeSet<Person> set = new TreeSet<Person>(new PersonComparator()); // use custom Comparator here
// foreach Person in the list
for(Person person : list) {
// if the person isn't already in the set (meaning it's not a duplicate)
// add it to the set and the new list
if(!set.contains(person)) {
set.add(person);
newList.add(person);
}
// otherwise it's a duplicate so we don't do anything
}
return newList;
}
TreeSet、as the documentation says、“提供有保证的 log(n) 时间成本”中的 contains 操作。
我上面建议的方法需要O(n*log(n)) 时间,因为我们对每个列表元素执行contains 操作,但它也使用O(n) 空间来创建新列表和TreeSet。
如果您的列表非常大(空间非常重要)但处理速度不是问题,那么您可以删除每个找到的重复项,而不是将每个非重复项添加到列表中:
List<Person> getListWithoutDups(List<Person> list) {
TreeSet<Person> set = new TreeSet<Person>(new PersonComparator()); // use custom Comparator here
Person person;
// for every Person in the list
for(int i = 0; i < list.size(); i++) {
person = list.get(i);
// if the person is already in the set (meaning it is a duplicate)
// remove it from the list
if(set.contains(person) {
list.remove(i);
i--; // make sure to accommodate for the list shifting after removal
}
// otherwise add it to the set of non-duplicates
else {
set.add(person);
}
}
return list;
}
由于列表上的每个remove 操作都需要O(n) 时间(因为每次删除元素时列表都会移动),并且每个contains 操作需要log(n) 时间,因此这种方法将是O(n^2 log(n))及时。
但是,空间复杂度将减半,因为我们只创建 TreeSet 而不是第二个列表。