sort concurrent map entries by value

前端 未结 1 2009
北恋
北恋 2021-01-05 09:07

Is there any way to create a thread-safe implementation of Map that maintains it\'s entries sorted by value? I know I can create a thread-safe Map

相关标签:
1条回答
  • 2021-01-05 09:53

    Consider building a composite data structure for this. At a high level, do the following.

    First, implement Map.Entry to keep key-value pairs. The pair's ordering would be first by value, and then by key.

    private static class InternalEntry<K extends Comparable<K>,
                                       V extends Comparable<V>>
            implements Comparable<InternalEntry<K, V>>,
                       Map.Entry<K, V> {
        private final K _key;
        private final V _val;
    
        InternalEntry(K key, V val) {
            _key = key;
            _val = val;
        }
    
        public K getKey() {
            return _key;
        }
    
        public V getValue() {
            return _val;
        }
    
        public V setValue(V value) {
            throw new UnsupportedOperationException();
        }
    
        public int compareTo(InternalEntry<K, V> o) {
            int first = _val.compareTo(o._val);
            if (first != 0) {
                return first;
            }
            return _key.compareTo(o._key);
        }
    }
    

    The entire entry can be used as the key of an ordered map.

    But that map does not support efficient lookup of value by key. To achieve that, introduce another map, which maps keys to entries.

    The composite structure looks like this:

    class OrderedByValue<K extends Comparable<K>, V extends Comparable<V>> {
        private final Map<InternalEntry<K, V>, Boolean> _ordering = 
            new TreeMap<InternalEntry<K, V>, Boolean>();
    
        private final Map<K, InternalEntry<K, V>> _lookup = 
            new HashMap<K, InternalEntry<K, V>>();
    
        public V put(K key, V val) {
            InternalEntry<K, V> entry = new InternalEntry<K, V>(key, val);
            InternalEntry<K, V> old = _lookup.put(key, entry);
            if (old == null) {
                _ordering.put(entry, Boolean.TRUE);
                return null;
            }
            _ordering.remove(old);
            _ordering.put(entry, Boolean.TRUE);
            return old.getValue();
        }
    
        @SuppressWarnings({"unchecked"})
        public Iterable<Map.Entry<K, V>> entrySet() {
            Iterable entries = Collections.unmodifiableSet(_ordering.keySet());
            return (Iterable<Map.Entry<K, V>>) entries;
        }
    }
    

    Note that I've not supplied all the necessary code to implement a full Map -- let me know if you need help with the other methods.

    You also need to do some special case code in the InternalEntry's comparison implementation if null keys/values need to be supported.

    0 讨论(0)
提交回复
热议问题