簡體   English   中英

唯一包含一個鍵但在不同字段上排序的集合

[英]Set that uniquely contains a key but ordered on different field

我正在尋找一個 Java 集合,可能在標准庫中,它能夠收集以下結構:

class Item {
    String key;
    double score;
}

並具有以下屬性:

  • 只允許一個具有相同鍵的項目(如一組)
  • 在最大 O(logn) 中插入、刪除、檢查是否存在
  • 按分數排序的遍歷,在最大 O(logn) 中找到下一個

據我所知,標准 OrderedSet 必須具有與 equals() 接口一致的可比較接口,但我的情況並非如此,因為具有不同鍵的兩個項目可能具有相同的分數。

事實上,我注意到 TreeSet 使用返回 0 的比較器來檢查該項目是否已經存在。

有什么建議嗎?

我不認為存在這樣的結構。 您沒有指定遍歷性能要求,因此您可以使用普通的 Set 並將值添加到列表中,然后按分數對該列表進行排序以進行遍歷。

HashSet 不保證其元素的任何順序。 如果您需要此保證,請考慮使用 TreeSet 來保存您的元素,但要通過鍵實現唯一性並保持恆定時間有效地覆蓋hashCode()equals() ,如下所示:

class Item {
    String key;
    double score;

    public Item(String key, double score) {
        this.key = key;
        this.score = score;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Item item = (Item) o;
        return key.equals(item.key);
    }

    @Override
    public int hashCode() {
        return Objects.hash(key);
    }

    @Override
    public String toString() {
        return "Item{" +
                "key='" + key + '\'' +
                ", score=" + score +
                '}';
    }
}

// main
public static void main(String[] args) {

        Set<Item> itemSet = new HashSet<>();

        itemSet.add(new Item("1", 1));
        itemSet.add(new Item("1", 2));
        itemSet.add(new Item("2", 1));

        //to get a sorted TreeSet
        //Add all your objects to the TreeSet, you will get a sorted Set.
        //TreeSet myTreeSet = new TreeSet();
        //myTreeSet.addAll(itemSet);
        //System.out.println(myTreeSet);
}

output:

Item{key='1', score=1.0}
Item{key='2', score=1.0}

感謝那些讓我思考他們的評論和答案的人。 我相信我們可以通過使用來達到要求:

TreeMap<Double, HashSet<Item>>

只是因為(我沒說過)兩個相同的鍵產生相同的分數; 但更一般地說,有兩個集合映射就足夠了:一個(有序)以排序字段為鍵,另一個(未排序)以唯一字段為鍵。

現在插入已放寬到O(log n) ,您可以使用雙集來執行此操作,即實現您自己的集,在幕后維護 2 個集。

如果您可以修改 class Item以實現equals()hashCode()以僅使用key字段,那將是最好的。 在那種情況下,您的 class 將使用HashSetTreeSet 如果hashCode()涵蓋的不僅僅是key段,則使用兩個TreeSet對象。

final class ItemSet implements NavigableSet<Item> {

    private final Set<Item> keySet = new HashSet<>();
    //                           or: new TreeSet<>(Comparator.comparing(Item::getKey));
    private final TreeSet<Item> navSet = new TreeSet<>(Comparator.comparingDouble(Item::getScore)
                                                                 .thenComparing(Item::getKey));

    //
    // Methods delegating to keySet for unique key access and for unordered access
    //

    @Override public boolean contains(Object o) { return this.keySet.contains(o); }
    @Override public boolean containsAll(Collection<?> c) { return this.keySet.containsAll(c); }
    @Override public int size() { return this.keySet.size(); }
    @Override public boolean isEmpty() { return this.keySet.isEmpty(); }

    //
    // Methods delegating to navSet for ordered access
    //

    @Override public Comparator<? super Item> comparator() { return this.navSet.comparator(); }
    @Override public Object[] toArray() { return this.navSet.toArray(); }
    @Override public <T> T[] toArray(T[] a) { return this.navSet.toArray(a); }
    @Override public Item first() { return this.navSet.first(); }
    @Override public Item last() { return this.navSet.last(); }
    @Override public Item lower(Item e) { return this.navSet.lower(e); }
    @Override public Item floor(Item e) { return this.navSet.floor(e); }
    @Override public Item ceiling(Item e) { return this.navSet.ceiling(e); }
    @Override public Item higher(Item e) { return this.navSet.higher(e); }

    //
    // Methods delegating to both keySet and navSet for mutation of this set
    //

    private final class ItemSetIterator implements Iterator<Item> {
        private final Iterator<Item> iterator = ItemSet.this.navSet.iterator();
        private Item keyToRemove;
        @Override
        public boolean hasNext() {
            return iterator.hasNext();
        }
        @Override
        public Item next() {
            keyToRemove = iterator.next();
            return keyToRemove;
        }
        @Override
        public void remove() {
            iterator.remove();
            ItemSet.this.keySet.remove(keyToRemove);
            keyToRemove = null;
        }
    }

    @Override
    public Iterator<Item> iterator() {
        return new ItemSetIterator();
    }
    @Override
    public void clear() {
        this.keySet.clear();
        this.navSet.clear();
    }
    @Override
    public boolean add(Item e) {
        if (! this.keySet.add(e))
            return false; // item already in set
        if (! this.navSet.add(e))
            throw new IllegalStateException("Internal state is corrupt");
        return true;
    }
    @Override
    public boolean remove(Object o) {
        if (! this.keySet.remove(o))
            return false; // item not in set
        if (! this.navSet.remove(o))
            throw new IllegalStateException("Internal state is corrupt");
        return true;
    }
    @Override
    public boolean addAll(Collection<? extends Item> c) {
        boolean changed = false;
        for (Item item : c)
            if (add(item))
                changed = true;
        return changed;
    }
    @Override
    public boolean removeAll(Collection<?> c) {
        boolean changed = false;
        for (Object o : c)
            if (remove(o))
                changed = true;
        return changed;
    }
    @Override
    public boolean retainAll(Collection<?> c) {
        throw new UnsupportedOperationException("Not yet implemented");
    }
    @Override
    public Item pollFirst() {
        throw new UnsupportedOperationException("Not yet implemented");
    }
    @Override
    public Item pollLast() {
        throw new UnsupportedOperationException("Not yet implemented");
    }
    @Override
    public NavigableSet<Item> descendingSet() {
        throw new UnsupportedOperationException("Not yet implemented");
    }
    @Override
    public Iterator<Item> descendingIterator() {
        throw new UnsupportedOperationException("Not yet implemented");
    }
    @Override
    public SortedSet<Item> headSet(Item toElement) {
        throw new UnsupportedOperationException("Not yet implemented");
    }
    @Override
    public NavigableSet<Item> headSet(Item toElement, boolean inclusive) {
        throw new UnsupportedOperationException("Not yet implemented");
    }
    @Override
    public SortedSet<Item> tailSet(Item fromElement) {
        throw new UnsupportedOperationException("Not yet implemented");
    }
    @Override
    public NavigableSet<Item> tailSet(Item fromElement, boolean inclusive) {
        throw new UnsupportedOperationException("Not yet implemented");
    }
    @Override
    public SortedSet<Item> subSet(Item fromElement, Item toElement) {
        throw new UnsupportedOperationException("Not yet implemented");
    }
    @Override
    public NavigableSet<Item> subSet(Item fromElement, boolean fromInclusive, Item toElement, boolean toInclusive) {
        throw new UnsupportedOperationException("Not yet implemented");
    }

}

只允許一個具有相同鍵的項目(如一組)

您的Item class 應該僅使用key屬性實現 hashCode() 和 equals()。

在恆定時間內插入,刪除,檢查是否存在

TreeSet add() 和 remove() 是 O(ln N),因此它們不符合您的條件。

HashSet add() 和 remove() 通常是 O(1)。

按分數排序的遍歷

您在這里的性能要求是什么? 您將多久遍歷一次集合? 如果您主要是添加和刪除項目而很少遍歷它,那么您可以在遍歷操作期間將HashSet復制到TreeSet

暫無
暫無

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

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