[英]Cross compare ArrayList elements and remove duplicates
我有一個ArrayList<MyObject>
,它可能(或可能不)包含我需要從List中刪除的MyObject
重復項。 如果我要在兩個for循環中迭代列表並與每個其他項交叉檢查每個項目,我怎么能以一種我不必檢查重復的方式執行此操作。
我只需要檢查每個項目一次,所以比較A:B
就足夠了 - 我不想再比較B:A
,因為我已經這樣做了。
此外; 我可以在循環時從列表中刪除重復項嗎? 或者會以某種方式打破列表和我的循環?
編輯:好的,我忘記了第一個答案的重要部分: MyObject
的副本不僅僅意味着Java方式意味着Object.equals(Object) ,但我需要能夠使用我自己的算法比較對象,如MyObject
的相等性是使用一種算法來計算的,該算法以我需要實現的特殊方式檢查Object的字段!
此外,我不能只是覆蓋MyObject
euqals
,因為有幾種不同的算法實現了不同的策略來檢查兩個MyObject
的相等性 - 例如,有一個簡單的HashComparer
和一個更復雜的EuclidDistanceComparer
,兩者都是AbstractComparers
實現不同的算法public abstract boolean isEqual(MyObject obj1, MyObject obj2);
對列表進行排序,重復項將彼此相鄰,使其易於識別和刪除。 只需瀏覽列表,記住上一個項目的值,以便將其與當前項目進行比較。 如果它們相同,請刪除當前項目。
如果您使用普通的for
-loop來瀏覽列表,則可以控制當前位置。 這意味着當你移除一個項目時,你可以減少位置( n--
),這樣下一次循環就會訪問相同的位置(現在是下一個項目)。
您需要在排序中提供自定義比較嗎? 那不是那么難:
Collections.sort(myArrayList, new Comparator<MyObject>() {
public int compare(MyObject o1, MyObject o2) {
return o1.getThing().compareTo(o2.getThing());
}
});
我編寫了這個例子,以便getThing().compareTo()
代表您想要比較兩個對象的任何內容。 必須返回一個整數,如果它們相同則為零,如果o1大於o2,則返回大於1;如果o1小於o2,則返回-1。 如果getThing()
返回一個String
或一個Date
,那么你將全部設置,因為這些類已經有了compareTo
方法。 但是您可以在自定義Comparator
放置所需的任何代碼。
創建一個集合,如果排序不重要,它將自動刪除重復項。
Set<MyObject> mySet = new HashSet<MyObject>(yourList);
實例化一個新的基於集合的集合HashSet。 不要忘記為MyObject實現equals和hashcode。
祝好運!
如果訂單不重要,您可以將列表的元素放入Set
:
Set<MyObject> mySet = new HashSet<MyObject>(yourList);
重復項將自動刪除。
如果排序很重要,那么您可以手動檢查重復項,例如使用此代碼段:
// Copy the list.
ArrayList<String> newList = (ArrayList<String>) list.clone();
// Iterate
for (int i = 0; i < list.size(); i++) {
for (int j = list.size() - 1; j >= i; j--) {
// If i is j, then it's the same object and don't need to be compared.
if (i == j) {
continue;
}
// If the compared objects are equal, remove them from the copy and break
// to the next loop
if (list.get(i).equals(list.get(j))) {
newList.remove(list.get(i));
break;
}
System.out.println("" + i + "," + j + ": " + list.get(i) + "-" + list.get(j));
}
}
這將刪除所有重復項,將最后一個重復值保留為原始條目。 此外,它只會檢查每個組合一次。
Java Streams使它更加優雅:
List<Integer> newList = oldList.stream()
.distinct()
.collect(Collectors.toList());
如果您需要根據自己的定義考慮兩個對象相等,則可以執行以下操作:
public static <T, U> Predicate<T> distinctByProperty(Function<? super T, ?> propertyExtractor) {
Set<Object> seen = ConcurrentHashMap.newKeySet();
return t -> seen.add(propertyExtractor.apply(t));
}
(作者Stuart Marks )
然后你可以這樣做:
List<MyObject> newList = oldList.stream()
.filter(distinctByProperty(t -> {
// Your custom property to use when determining whether two objects
// are equal. For example, consider two object equal if their name
// starts with the same character.
return t.getName().charAt(0);
}))
.collect(Collectors.toList());
當Iterator
(通常用於for-each循環)循環遍歷數組時,您無法修改列表。 這將拋出ConcurrentModificationException
。 如果使用for循環對其進行循環,則可以修改該數組。 然后,您必須控制迭代器位置(在刪除條目時遞減它)。
或http://docs.oracle.com/javase/6/docs/api/java/util/SortedSet.html如果您需要排序順序..
編輯 :如何從http://docs.oracle.com/javase/6/docs/api/java/util/TreeSet.html派生,它將允許您在施工時傳入比較器。 您重寫add()
以使用Comparator而不是equals()
- 這將使您可以靈活地創建根據Comparator訂購的不同集合,並且它們將實現您的“Equality”-Strategy。
不要忘記equals()
和hashCode()
雖然......
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.