Я знаю, как "преобразовать" простую Java List
из Y
-> Z
, то есть:
List<String> x;
List<Integer> y = x.stream()
.map(s -> Integer.parseInt(s))
.collect(Collectors.toList());
Теперь я хотел бы сделать то же самое с картой, то есть:
INPUT:
{
"key1" -> "41", // "41" and "42"
"key2" -> "42 // are Strings
}
OUTPUT:
{
"key1" -> 41, // 41 and 42
"key2" -> 42 // are Integers
}
Решение не должно ограничиваться String
-> Integer
. Прямо как вList
примере выше, я бы хотел вызвать любой метод (или конструктор).
java
mapreduce
java-8
java-stream
collectors
Бенджамин М
источник
источник
e -> e.getKey()
наMap.Entry::getKey
. Но это вопрос вкуса / стиля программирования.Вот несколько вариантов ответа Сотириоса Делиманолиса , который был довольно хорош для начала (+1). Учтите следующее:
Пара очков здесь. Во-первых, это использование подстановочных знаков в генериках; это делает функцию несколько более гибкой. Подстановочный знак был бы необходим, если, например, вы хотите, чтобы у выходной карты был ключ, который является суперклассом ключа входной карты:
(Существует также пример значений карты, но он действительно надуманный, и я признаю, что использование ограниченного символа подстановки для Y помогает только в крайних случаях.)
Второй момент заключается в том, что вместо запуска потока над входной картой
entrySet
я запускал его черезkeySet
. Это делает код немного чище, я думаю, за счет необходимости извлекать значения из карты, а не из записи карты. Между прочим, у меня изначально былkey -> key
первый аргумент,toMap()
и по какой-то причине это не удалось с ошибкой вывода типа. Поменял его на(X key) -> key
работавший, как и сделалFunction.identity()
.Еще один вариант заключается в следующем:
Это использует
Map.forEach()
вместо потоков. Это еще проще, я думаю, потому что это обходится без коллекционеров, которые несколько неуклюжи для использования с картами. Причина в том, чтоMap.forEach()
ключ и значение задаются как отдельные параметры, тогда как поток имеет только одно значение - и вам нужно выбрать, использовать ли ключ или запись карты в качестве этого значения. С другой стороны, этому не хватает богатого, плавного совершенства других подходов. :-)источник
Function.identity()
может показаться классным, но поскольку первое решение требует поиска по карте / хешу для каждой записи, в то время как все остальные решения этого не делают, я бы не рекомендовал это делать.Общее решение, как так
пример
источник
Функция Guava -
Maps.transformValues
это то, что вы ищете, и она хорошо работает с лямбда-выражениями:источник
java.util.Function
, у вас есть два варианта. 1. Избегайте проблемы, используя лямбду, чтобы позволить выводу типа Java разобраться с этим. 2. Используйте ссылку на метод, такую как javaFunction :: apply, чтобы создать новую лямбду, которую может определить вывод типа.Это должно быть на 100% функционально и свободно? Если нет, то как насчет этого, который настолько короток, насколько это возможно:
( если вы можете жить со стыдом и чувством вины от объединения потоков с побочными эффектами )
источник
Моя библиотека StreamEx, которая расширяет стандартный потоковый API, предоставляет
EntryStream
класс, который лучше подходит для преобразования карт:источник
Альтернатива, которая всегда существует для целей обучения, состоит в том, чтобы создать свой собственный сборщик с помощью Collector.of (), хотя сборщик JDK toMap () здесь краткий (+1 здесь ).
источник
map2.entrySet().forEach(entry -> { if (map1.containsKey(entry.getKey())) { map1.get(entry.getKey()).merge(entry.getValue()); } else { map1.put(entry.getKey(),entry.getValue()); } }); return map1
иначе значения будут потеряны при уменьшении.Если вы не возражаете против использования сторонних библиотек, моя библиотека cyclops-реагирует на расширения для всех типов JDK Collection , включая Map . Мы можем просто преобразовать карту напрямую, используя оператор «карта» (по умолчанию карта действует на значения в карте).
bimap может использоваться для преобразования ключей и значений одновременно
источник
Декларативное и более простое решение будет:
yourMutableMap.replaceAll ((ключ, val) -> return_value_of_bi_your_function); В северном направлении знать, что вы изменяете свое состояние карты. Так что это может быть не то, что вы хотите.
Приветствия: http://www.deadcoderising.com/2017-02-14-java-8-declarative-ways-of-modifying-a-map-using-compute-merge-and-replace/
источник