簡體   English   中英

交叉比較ArrayList元素並刪除重復項

[英]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 8

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());

Futhermore

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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM