сортировать одновременные записи карты по значению - PullRequest
7 голосов
/ 10 мая 2011

Есть ли способ создать поточно-ориентированную реализацию Map, которая поддерживает записи, отсортированные по значению?Я знаю, что могу создать потокобезопасный Map, например,

ConcurrentMap<String, Double> rankings = new ConcurrentHashMap<String, Double>();

. Затем я могу отсортировать записи по значению, передав их служебному методу, например так:

public static <K, V extends Comparable<? super V>> Map<K, V> sortByValue(Map<K, V> map) {
    List<Map.Entry<K, V>> list = new LinkedList<Map.Entry<K, V>>(map.entrySet());
    Collections.sort(list, new Comparator<Map.Entry<K, V>>() {
        @Override
        public int compare(Map.Entry<K, V> o1, Map.Entry<K, V> o2) {
            return (o1.getValue()).compareTo(o2.getValue());
        }
    });

    Map<K, V> result = new LinkedHashMap<K, V>();
    for (Map.Entry<K, V> entry : list) {
        result.put(entry.getKey(), entry.getValue());
    }
    return result;
}

Но я ищу поточно-ориентированный Map, который поддерживает записей, отсортированных по значению, так что мне не нужно вызывать метод, такой как выше, после каждой вставки /удаление, чтобы сохранить записи, отсортированные по значению.Я думаю, я ищу реализацию, которая сочетает в себе поведение ConcurrentHashMap и LinkedHashMap, но еще не нашла.

ConcurrentSkipListMap почти обеспечивает то, что я хочу, но, похоже, поддерживает только сортировку по значению ключа.

1 Ответ

2 голосов
/ 10 мая 2011

Рассмотрите возможность создания составной структуры данных для этого. На высоком уровне сделайте следующее.

Во-первых, реализуйте Map.Entry, чтобы сохранить пары ключ-значение. Порядок пары будет сначала по значению, а затем по ключу.

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

Вся запись может использоваться в качестве клавиши заказанной карты.

Но эта карта не поддерживает эффективный поиск значения по ключу. Для этого введите еще одну карту, которая сопоставляет ключи с записями.

Составная структура выглядит следующим образом:

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;
    }
}

Обратите внимание, что я не предоставил весь необходимый код для реализации полной карты - дайте мне знать, если вам нужна помощь с другими методами.

Вам также нужно сделать какой-то особый код в реализации сравнения InternalEntry, если необходимо поддерживать нулевые ключи / значения.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...