有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

唯一包含密钥但在不同字段上排序的java集

我正在寻找一个Java集合,可能在标准库中,它能够收集以下结构:

class Item {
    String key;
    double score;
}

并具有以下特性:

  • 只允许一个具有相同密钥的项目(如一套)
  • 插入、移除、检查max O(logn)中的存在
  • 按分数排序的遍历,在max O(logn)中查找下一个

据我所知,标准OrderedSet必须具有与equals()接口一致的可比接口,但这不是我的情况,因为具有不同键的两个项可能具有相同的分数

事实上,我注意到TreeSet使用返回0的比较器来检查项目是否已经存在

有什么建议吗


共 (5) 个答案

  1. # 1 楼答案

    哈希集不保证其元素的任何顺序。如果需要此保证,请考虑使用树集来保存元素。 但是为了通过键实现唯一性并保持恒定时间覆盖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);
    }
    

    输出:

    Item{key='1', score=1.0}
    Item{key='2', score=1.0}
    
  2. # 2 楼答案

    我认为不存在这样的结构。您没有指定遍历性能要求,因此可以使用一个普通集,将值添加到列表中,并按遍历分数对该列表进行排序

  3. # 3 楼答案

    Only one Item with the same key is allowed (like a set)

    您的Item类应该只使用key属性实现hashCode()和equals()

    insert, remove, check existance in constant time

    TreeSetadd()和remove()是O(ln N),因此它们不符合您的条件

    添加()和删除()通常是O(1)

    traversal ordered by score

    你在这里的表现要求是什么?您将多久浏览一次该系列?如果主要是添加和删除项目,而很少遍历它,那么可以在遍历操作期间将HashSet复制到TreeSet

  4. # 4 楼答案

    现在insert已被放宽为O(logn),您可以使用一个双集合来实现这一点,即实现您自己的集合,在幕后维护两个集合

    最好是修改类Item来实现equals(),而hashCode()只使用key字段。在这种情况下,您的类将使用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");
        }
    
    }
    
  5. # 5 楼答案

    感谢那些用他们的评论和回答让我思考的人。我相信我们可以通过以下方式达到要求:

    TreeMap<Double, HashSet<Item>>
    

    只是因为(我没有说过)两个相等的键产生相同的分数;但更一般地说,有两个集合映射就足够了:一个(有序)以排序字段作为键,另一个(不有序)以唯一字段作为键