#java #collections #treemap
#java #Коллекции #древовидная карта
Вопрос:
Привет, у меня есть следующий код
TreeMap mp = new TreeMap<String,TreeMap<String,Integer>();
mp.put(line,(new TreeMap<String,Integer>()));
Теперь, если я хочу вставить данные в новое пустое дерево <Строка, целое число>, созданное «mp», как мне это сделать?
Комментарии:
1. Какой тип
mp
? Что такоеEmptyTree
? Вы имели в видуTreeMap
?
Ответ №1:
Существует множество способов сделать это.
Во-первых, вы могли бы просто сохранить ссылку вокруг:
var map = new TreeMap<String,Integer>();
mp.put(line, map);
// can du stuff with map now
Во-вторых, вы можете прочитать значение обратно с карты — очевидно, это не очень эффективно, но я бы включил его для полноты картины:
mp.put(line,(new TreeMap<String,Integer>()));
var map = mp.get(line);
Самым элегантным решением было бы использовать computeIfAbsent
:
var map = mp.computeIfAbsent(line, line -> new TreeMap<String,Integer>());
// do stuff with map
computeIfAbsent
возвращает значение, которое уже присутствует на карте, или иным образом вычисляет лямбда-выражение и помещает его в карту, и возвращает это значение.
Из JavaDoc:
Если указанный ключ еще не связан со значением (или сопоставлен
null
), пытается вычислить его значение с помощью заданной функции сопоставления и вводит его в эту карту, еслиnull
.Если функция сопоставления возвращает значение null, сопоставление не записывается. Если функция сопоставления сама выдает (непроверенное) исключение, исключение повторно отбрасывается, и сопоставление не записывается. Наиболее распространенным использованием является создание нового объекта, служащего в качестве начального отображенного значения или запоминаемого результата, как в:
map.computeIfAbsent(key, k -> new Value(f(k)));
Или реализовать многозначную карту
Map<K,Collection<V>>
, поддерживающую несколько значений для каждого ключа:
map.computeIfAbsent(key, k -> new HashSet<V>()).add(v);
Функция отображения не должна изменять эту карту во время вычисления
Преимущество computeIfAbsent
заключается в том, что вам не нужно проверять, присутствует ли значение уже на карте, и нет опасности переопределения старых значений.
Ответ №2:
Извлеките его с помощью TreeMap#get(java.lang.Object)
и поместите значение, используя один из методов put из извлеченного TreeMap
, например TreeMap#put(K, V)
.
Пример:
// notice the diamond operator used here -- it improves your code readability!!
TreeMap<String,TreeMap<String,Integer>> mp = new TreeMap<>();
// you don't need to qualify the type again because of the diamond operator
mp.put(line, new TreeMap<>());
// put a new value into the newly created TreeMap
Integer value = 1;
mp.get(line).put("your string key", value);
Для полноты картины: если вы используете Java 8 или новее, чтобы сделать код еще более чистым, вы можете использовать computeIfAbsent
:.
TreeMap<String,TreeMap<String,Integer>> mp = new TreeMap<>();
Integer value = 1;
mp.computeIfAbsent(line, key -> new TreeMap<>()).put("your string key", value);
Ответ №3:
Опубликованный вами фрагмент кода имеет несколько проблем:
TreeMap mp = new TreeMap<String,TreeMap<String,Integer>();
^ add type specifier ^missing `>`
В первой строке вы не указали общий тип, поэтому ваш mp
тип является rawtype — поэтому вызов get
на нем возвращает что-то типа Object
— для использования этого потребуется приведение, и это не рекомендуется. Допустимыми версиями являются:
TreeMap<String,TreeMap<String,Integer>> mp = new TreeMap<>();
или
var mp = new TreeMap<String,TreeMap<String,Integer>>();
обе эти версии позволяют вам получать доступ к вложенным картам без приведений:
TreeMap<String, Integer> m = mp.get(line);
Но, как уже упоминали другие, поместить значение в map в случае, если оно отсутствует, но использовать существующее значение в противном случае — это именно то, для чего предназначен метод computeIfAbsent
— использование, которое вы можете написать, например:
var line = "line";
var mp = new TreeMap<String,TreeMap<String,Integer>>();
var m = mp.computeIfAbsent(line, k -> new TreeMap<>());
m.put("content", 5);
System.out.println(mp);
Выходной сигнал:
{line={content=5}}