Упорядоченная карта Java

Есть ли в Java объект, который действует как карта для хранения и доступа к парам ключ / значение, но может возвращать упорядоченный список ключей и упорядоченный список значений, чтобы списки ключей и значений были в одном и том же порядке?

Итак, в качестве объяснения по коду, я ищу что-то, что ведет себя как мой вымышленный OrderedMap:

OrderedMap<Integer, String> om = new OrderedMap<>();
om.put(0, "Zero");
om.put(7, "Seven");

String o = om.get(7); // o is "Seven"
List<Integer> keys = om.getKeys();
List<String> values = om.getValues();

for(int i = 0; i < keys.size(); i++)
{
    Integer key = keys.get(i);
    String value = values.get(i);
    Assert(om.get(key) == value);
}

8 ответов

Решение

Интерфейс SortedMap (с реализацией TreeMap) должен быть вашим другом.

Интерфейс имеет методы:

  • keySet() который возвращает набор ключей в порядке возрастания
  • values() который возвращает коллекцию всех значений в порядке возрастания соответствующих ключей

Так что этот интерфейс полностью соответствует вашим требованиям. Однако ключи должны иметь осмысленный порядок. В противном случае вы можете использовать LinkedHashMap, где порядок определяется порядком вставки.

Существует ли объект, который действует как карта для хранения и доступа к парам ключ / значение, но может возвращать упорядоченный список ключей и упорядоченный список значений, чтобы списки ключей и значений были в одном и том же порядке?

Вы ищете java.util.LinkedHashMap. Вы получите список пар Map.Entry, которые всегда повторяются в одном и том же порядке. Этот порядок совпадает с порядком, в котором вы помещаете элементы. В качестве альтернативы используйте java.util.SortedMap, где ключи должны либо иметь естественный порядок, либо указывать его Comparator,

LinkedHashMap поддерживает порядок ключей.

java.util.LinkedHashMap, кажется, работает так же, как обычный HashMap в противном случае.

tl;dr

Хранить Map< Integer , String > в порядке, отсортированном по ключу, используйте любой из двух классов, реализующих SortedMap/NavigableMap интерфейсы:

  • TreeMap
  • ConcurrentSkipListMap

Если вы управляете картой в одном потоке, используйте первый, TreeMap. При манипулировании между потоками используйте второй,ConcurrentSkipListMap.

Подробнее см. В таблице ниже и в следующем обсуждении.

Детали

Вот составленная мной графическая таблица, показывающая особенности десяти Map реализации в комплекте с Java 11.

В NavigableMap интерфейс это то, что SortedMap должен был быть на первом месте. ВSortedMap логически должен быть удален, но не может быть удален, поскольку некоторые сторонние реализации карт могут использовать интерфейс.

Как видно из этой таблицы, только два класса реализуют SortedMap/NavigableMap интерфейсы:

Оба они хранят ключи в отсортированном порядке, либо в их естественном порядке (используя compareTo метод Comparable(https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/lang/Comparable.html) интерфейс) или с помощью Comparator реализацию вы пройдете. Разница между этими двумя классами в том, что второй, ConcurrentSkipListMap, является потокобезопасным, с высокой степенью параллелизма.

См. Также столбец Порядок итераций в таблице ниже.

  • В LinkedHashMap class возвращает свои записи в том порядке, в котором они были изначально вставлены.
  • EnumMap возвращает записи в том порядке, в котором определен класс перечисления ключа. Например, карта, на которой сотрудник какой день недели работает (Map< DayOfWeek , Person >) использует DayOfWeek enum класс, встроенный в Java. Это перечисление определяется первым понедельником и последним воскресеньем. Таким образом, записи в итераторе появятся именно в таком порядке.

Остальные шесть реализаций не обещают порядок, в котором они сообщают свои записи.

Я думаю, что ближайшая коллекция, которую вы получите из фреймворка, это SortedMap

Вы можете использовать интерфейс NavigableMap, к которому можно получить доступ и пройти в порядке возрастания или убывания ключа. Этот интерфейс предназначен для замены интерфейса SortedMap. Навигационная карта обычно сортируется в соответствии с естественным порядком ее ключей или с помощью компаратора, предоставляемого во время создания карты.

Существует три наиболее полезных реализации: TreeMap, ImmutableSortedMap и ConcurrentSkipListMap.

Пример TreeMap:

TreeMap<String, Integer> users = new TreeMap<String, Integer>();
users.put("Bob", 1);
users.put("Alice", 2);
users.put("John", 3);

for (String key: users.keySet()) {
  System.out.println(key + " (ID = "+ users.get(key) + ")");
}

Выход:

Alice (ID = 2)
Bob (ID = 1)
John (ID = 3)

Я думаю, что интерфейс SortedMap реализует то, что вы просите, и TreeMap реализует это.

http://java.sun.com/j2se/1.5.0/docs/api/java/util/SortedMap.html http://java.sun.com/j2se/1.5.0/docs/api/java/util/TreeMap.html

Начиная с Java 6 существует неблокирующая поточно-ориентированная альтернатива TreeMap. Смотрите ConcurrentSkipListMap.

Современная версия Java ответа Штеффи Керан

public class Solution {
    public static void main(String[] args) {
        // create a simple hash map and insert some key-value pairs into it
        Map<String, Integer> map = new HashMap<>();
        map.put("Python", 3);
        map.put("C", 0);
        map.put("JavaScript", 4);
        map.put("C++", 1);
        map.put("Golang", 5);
        map.put("Java", 2);
        // Create a linked list from the above map entries
        List<Map.Entry<String, Integer>> list = new LinkedList<>(map.entrySet());
        // sort the linked list using Collections.sort()
        list.sort(Comparator.comparing(Map.Entry::getValue));
        list.forEach(System.out::println);
    }
}

Я использовал карту Simple Hash, связанный список и коллекции для сортировки карты по значениям.

import java.util.*;
import java.util.Map.*;
public class Solution {

    public static void main(String[] args) {
        // create a simple hash map and insert some key-value pairs into it
        Map<String, Integer> map = new HashMap<String, Integer>();
        map.put("Python", 3);
        map.put("C", 0);
        map.put("JavaScript", 4);
        map.put("C++", 1);
        map.put("Golang", 5);
        map.put("Java", 2);
        // Create a linked list from the above map entries
        List<Entry<String, Integer>> list = new LinkedList<Entry<String, Integer>>(map.entrySet());
        // sort the linked list using Collections.sort()
        Collections.sort(list, new Comparator<Entry<String, Integer>>(){
        @Override
         public int compare(Entry<String, Integer> m1, Entry<String, Integer> m2) {
        return m1.getValue().compareTo(m2.getValue());
        }
      });
      for(Entry<String, Integer> value: list) {
         System.out.println(value);
     }
   }
}

Выход:

C=0
C++=1
Java=2
Python=3
JavaScript=4
Golang=5
Другие вопросы по тегам