簡體   English   中英

Java:均衡器? (從對象集合中刪除重復項)

[英]Java: Equalator? (removing duplicates from a collection of objects)

我有一堆類Puzzle 我重寫了equals()hashCode() 當需要向用戶展示解決方案時,我想過濾掉所有“相似”的難題(按照我定義的標准),因此用戶只能看到其中的一個。

相似性是可傳遞的。

例:

Result of computations:
A    (similar to A)
B    (similar to C)
C
D

在這種情況下,只會向用戶顯示A或D以及B或C-但不會顯示兩個類似的拼圖。 兩個類似的難題同樣有效。 重要的是不要同時向用戶顯示它們。

為此,我想使用禁止重復的ADT。 但是,我不想更改equals()hashCode()方法來返回有關相似性的值。 在這種情況下是否可以使用某些Equalator (例如Comparator 還是我應該采取另一種方式?

我正在上的課是一個拼圖,它保持字母網格。 (如拼字游戲。)如果“拼圖”包含相同的單詞,但方向不同,則認為它是相似的。 因此,以下內容令人困惑:

                                    (2, 2): A           
                                    (2, 1): C           
                                    (2, 0): T

將類似於:

                    (1, 2): A           
                    (1, 1): C           
                    (1, 0): T      

我將使用一個包裝器類來相應地覆蓋equalshashCode

private static class Wrapper {
    public static final Puzzle puzzle;
    public Wrapper(Puzzle puzzle) { 
        this.puzzle = puzzle; 
    }
    @Override 
    public boolean equals(Object object) {
        // ...
    }
    @Override 
    public int hashCode() {
        // ...
    }
}

然后將所有謎題包起來,將它們放在地圖中,然后再次將它們取出…

public Collection<Collection<Puzzle>> method(Collection<Puzzles> puzzles) {
    Map<Wrapper,<Collection<Puzzle>> map = new HashMap<Wrapper,<Collection<Puzzle>>();
    for (Puzzle each: puzzles) {
        Wrapper wrapper = new Wrapper(each);
        Collection<Puzzle> coll = map.get(wrapper);
        if (coll == null) map.put(wrapper, coll = new ArrayList<Puzzle>());
        coll.add(puzzle);
    }
    return map.values();
}

好的,您可以使用一種方法來測量對象之間的相似性。 這意味着它們形成一個度量空間

問題是,您的空間還是像普通的三維空間還是整數之類的歐幾里德空間 如果是這樣,則可以使用二進制空間分區 ,無論您擁有多少維。

(問題基本上是:您的對象和n維實數向量之間是否存在同態?如果是,那么您可以使用技術來測量n維空間中點的緊密度。)

a euclidean space then you've got a bigger problem. 現在,如果它歐幾里德空間,那么您將面臨更大的問題。 程序員可能最熟悉的非歐幾里德空間的一個示例是字符串之間的Levenshtein距離

of any algorithms that would do that without O(n 2 ) time. 如果您的問題類似於查看字符串與已存在的字符串列表的相似程度,那么我不沒有O(n 2 )時間就能做到的算法。 也許那里有一些。


但是另一個重要的問題是:您有多少時間? 有多少個物體? 如果您有時間,或者您的數據集足夠小,以至於O(n 2 )算法是可行的,那么您僅需遍歷對象列表以查看其是否低於某個閾值。 如果是這樣,請拒絕它。

只需重載AbstractCollection並替換Add函數即可。 使用ArrayList或其他。 您的代碼看起來像這樣

class SimilarityRejector<T> extends AbstractCollection<T>{
     ArrayList<T> base;
     double threshold;

    public SimilarityRejector(double threshold){
        base = new ArrayList<T>();
        this.threshold = threshold;
    }

    public void add(T t){
       boolean failed = false;
       for(T compare : base){
          if(similarityComparison(t,compare) < threshold) faled = true;
       }
       if(!failed) base.add(t);
     }

    public Iterator<T> iterator() {
        return base.iterator();
    }

    public int size() {
        return base.size();
    }
}

等等。顯然,T必須是您可以對其進行比較的某個類的子類。 如果您具有歐幾里德度量標准,則可以使用空間分區,而不要遍歷其他所有項目。

  1. 使用比較器創建TreeSet
  2. 將所有元素添加到集合中
  3. 刪除所有重復項

恕我直言,最優雅的方式是由Gili(帶有自定義比較器的TreeSet)描述的。

但是,如果您想自己做,這似乎是最簡單,最清晰的解決方案:

/**
 * Distinct input list values (cuts duplications)
 * @param items items to process
 * @param comparator comparator to recognize equal items
 * @return new collection with unique values
 */
public static <T> Collection<T> distinctItems(List<T> items, Comparator<T> comparator) {
    List<T> result = new ArrayList<>();

    for (int i = 0; i < items.size(); i++) {
        T item = items.get(i);

        boolean exists = false;
        for (int j = 0; j < result.size(); j++) {
            if (comparator.compare(result.get(j), item) == 0) {
                exists = true;
                break;
            }
        }

        if (!exists) {
            result.add(item);
        }
    }

    return result;
}

通常,“相似性”不是傳遞關系。 因此,第一步是從等價而非相似的角度來考慮。 等價是自反的,對稱的和可傳遞的。

此處的簡單方法是定義一個難題包裝程序,該程序的equals()和hashCode()方法是根據所討論的等效關系實現的。

一旦有了,就將包裝的對象放到java.util.Set中,並過濾掉重復的對象。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

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