Переписывание значений в HashMap, которые находятся в ArrayList <String>
Скажем, у меня есть HashMap со строковыми клавишами и значениями Integer:
map = {cat=1, kid=3, girl=3, adult=2, human=5, dog=2, boy=2}
Я хочу переключать ключи и значения, помещая эту информацию в другую HashMap. Я знаю, что HashMap не может иметь дубликаты ключей, поэтому я попытался помещать информацию в HashMap с помощью Integer для ключей, которые будут отображаться в String ArrayList, чтобы я мог потенциально иметь одно целочисленное сопоставление с несколькими строками:
swap = {1=[cat], 2=[adult, dog, boy], 3=[kid, girl], 5=[human]}
Я попробовал следующий код:
HashMap<Integer, ArrayList<String>> swap = new HashMap<Integer, ArrayList<String>>();
for (String x : map.keySet()) {
for (int i = 0; i <= 5; i++) {
ArrayList<String> list = new ArrayList<String>();
if (i == map.get(x)) {
list.add(x);
swap.put(i, list);
}
}
}
Единственное различие в моем коде состоит в том, что я не усложнил код 5 в свой индекс; У меня есть метод, который находит самое высокое целочисленное значение в исходном HashMap и использовал это. Я знаю, что он работает правильно, потому что я получаю тот же результат, даже если я жестко кодирую 5, я просто не использовал его для экономии места.
Моя цель состоит в том, чтобы иметь возможность сделать это "разворот" с любым набором данных, иначе я мог бы просто записать код. Результат, полученный из приведенного выше кода, следующий:
swap = {1=[cat], 2=[boy], 3=[girl], 5=[human]}
Как вы можете видеть, моя проблема в том, что значение ArrayList удерживает только последнюю строну, которая была помещена в нее, а не собирать все из них. Как заставить ArrayList хранить каждую строку, а не только последнюю строку?
Ответы
Ответ 1
С помощью Java 8 вы можете сделать следующее:
Map<String, Integer> map = new HashMap<>();
map.put("cat", 1);
map.put("kid", 3);
map.put("girl", 3);
map.put("adult", 2);
map.put("human", 5);
map.put("dog", 2);
map.put("boy", 2);
Map<Integer, List<String>> newMap = map.keySet()
.stream()
.collect(Collectors.groupingBy(map::get));
System.out.println(newMap);
Выход будет:
{1=[cat], 2=[adult, dog, boy], 3=[kid, girl], 5=[human]}
Ответ 2
вы воссоздаете arrayList для каждой итерации, и я не могу понять, как это сделать с этой логикой, вот хороший способ, хотя и без необходимости проверять максимальное число:
for (Map.Entry<String, Integer> entry : map.entrySet()) {
String key = entry.getKey();
Integer value = entry.getValue();
List<String> get = swap.get(value);
if (get == null) {
get = new ArrayList<>();
swap.put(value, get);
}
get.add(key);
}
Ответ 3
Лучший способ - перебрать набор ключей исходной карты.
Также вы должны убедиться, что List присутствует для любого ключа целевой карты:
for (Map.Entry<String,Integer> inputEntry : map.entrySet())
swap.computeIfAbsent(inputEntry.getValue(),()->new ArrayList<>()).add(inputEntry.getKey());
Ответ 4
Это, очевидно, не лучшее решение, но подходит к проблеме так же, как вы сделали, заменив внутренние и внешние контуры, как показано ниже.
Map<String, Integer> map = new HashMap<String, Integer>();
map.put("cat", 1);
map.put("kid", 3);
map.put("girl", 3);
map.put("adult", 2);
map.put("human", 5);
map.put("dog", 2);
map.put("boy", 2);
HashMap<Integer, ArrayList<String>> swap = new HashMap<Integer, ArrayList<String>>();
for (Integer value = 0; value <= 5; value++) {
ArrayList<String> list = new ArrayList<String>();
for (String key : map.keySet()) {
if (map.get(key) == value) {
list.add(key);
}
}
if (map.containsValue(value)) {
swap.put(value, list);
}
}
Выход
{1 = [cat], 2 = [взрослый, собака, мальчик], 3 = [ребенок, девочка], 5 = [человек]}
Ответ 5
Лучший способ, которым я могу думать, - использовать Map.forEach
метод на существующей карте и Map.computeIfAbsent
на новой карте:
Map<Integer, List<String>> swap = new HashMap<>();
map.forEach((k, v) -> swap.computeIfAbsent(v, k -> new ArrayList<>()).add(k));
В качестве дополнительной заметки вы можете использовать оператор алмаза <>
для создания новой карты (нет необходимости повторять тип ключа и значение при вызове конструктора карты, поскольку компилятор сделает их вывод).
В качестве второй заметки хорошо использовать интерфейсные типы вместо конкретных типов, как для типичных типов параметров, так и для реальных типов. Вот почему я использовал List
и Map
вместо ArrayList
и HashMap
соответственно.
Ответ 6
Используя groupingBy
, как в ответ Джейкоба, но с Map.entrySet
для лучшей производительности, как предложенной Борисом:
// import static java.util.stream.Collectors.*
Map<Integer, List<String>> swap = map.entrySet()
.stream()
.collect(groupingBy(Entry::getValue, mapping(Entry::getKey, toList())));
Это использует еще два метода Collectors
: mapping
и toList
.
Если бы не эти две вспомогательные функции, решение могло бы выглядеть так:
Map<Integer, List<String>> swap = map.entrySet()
.stream()
.collect(
groupingBy(
Entry::getValue,
Collector.of(
ArrayList::new,
(list, e) -> {
list.add(e.getKey());
},
(left, right) -> { // only needed for parallel streams
left.addAll(right);
return left;
}
)
)
);
Или, используя toMap
вместо groupingBy
:
Map<Integer, List<String>> swap = map.entrySet()
.stream()
.collect(
toMap(
Entry::getValue,
(e) -> new ArrayList<>(Arrays.asList(e.getKey())),
(left, right) -> {
left.addAll(right);
return left;
}
)
);
Ответ 7
Это означает, что вы переопределяете значения instrad, добавляя их к уже созданному arraylist. Попробуйте следующее:
HashMap<Integer, ArrayList<String>> swapedMap = new HashMap<Integer, ArrayList<String>>();
for (String key : map.keySet()) {
Integer swappedKey = map.get(key);
ArrayList<String> a = swapedMap.get(swappedKey);
if (a == null) {
a = new ArrayList<String>();
swapedMap.put(swappedKey, a)
}
a.add(key);
}
У меня не было времени запустить его (извините, у меня нет компилятора Java), но должно быть почти нормально:)
Ответ 8
Вы можете использовать новый метод merge
в java-8 из Map
:
Map<Integer, List<String>> newMap = new HashMap<>();
map.forEach((key, value) -> {
List<String> values = new ArrayList<>();
values.add(key);
newMap.merge(value, values, (left, right) -> {
left.addAll(right);
return left;
});
});