-> List
에서 간단한 Java를 “변환”하는 방법을 알고 있습니다 .Y
Z
List<String> x;
List<Integer> y = x.stream()
.map(s -> Integer.parseInt(s))
.collect(Collectors.toList());
이제 기본적으로 Map과 동일하게 수행하고 싶습니다.
INPUT:
{
"key1" -> "41", // "41" and "42"
"key2" -> "42 // are Strings
}
OUTPUT:
{
"key1" -> 41, // 41 and 42
"key2" -> 42 // are Integers
}
솔루션은 String
-> 로 제한되지 않아야합니다 Integer
. List
위 의 예와 마찬가지로 모든 메소드 (또는 생성자)를 호출하고 싶습니다.
답변
Map<String, String> x;
Map<String, Integer> y =
x.entrySet().stream()
.collect(Collectors.toMap(
e -> e.getKey(),
e -> Integer.parseInt(e.getValue())
));
목록 코드만큼 좋지는 않습니다. 통화 Map.Entry
에서 새로운을 구성 할 수 없으므로 map()
작업이 collect()
통화에 혼합됩니다 .
답변
다음은 Sotirios Delimanolis의 답변에 대한 변형입니다 . (+1)로 시작하는 것이 좋습니다. 다음을 고려하세요:
static <X, Y, Z> Map<X, Z> transform(Map<? extends X, ? extends Y> input,
Function<Y, Z> function) {
return input.keySet().stream()
.collect(Collectors.toMap(Function.identity(),
key -> function.apply(input.get(key))));
}
여기 몇 점이 있습니다. 첫 번째는 제네릭에 와일드 카드를 사용하는 것입니다. 이것은 기능을 다소 유연하게 만듭니다. 예를 들어, 출력 맵이 입력 맵 키의 수퍼 클래스 인 키를 갖도록하려면 와일드 카드가 필요합니다.
Map<String, String> input = new HashMap<String, String>();
input.put("string1", "42");
input.put("string2", "41");
Map<CharSequence, Integer> output = transform(input, Integer::parseInt);
(지도의 값에 대한 예도 있지만 실제로 고안되어 있으며 Y에 대해 경계 와일드 카드를 사용하면 가장자리 경우에만 도움이된다는 것을 인정합니다.)
두 번째 포인트는 대신 입력지도의 이상 스트림을 실행하는 것입니다 entrySet
, 나는 위를 달렸다 keySet
. 이로 인해 맵 항목 대신 맵에서 값을 가져와야하는 비용으로 코드가 조금 더 깨끗해집니다. 우연히, 나는 처음 key -> key
에 첫 번째 주장으로 toMap()
있었고 어떤 이유로 타입 추론 오류로 실패했습니다. (X key) -> key
작동했던 것처럼 변경했습니다 Function.identity()
.
또 다른 변형은 다음과 같습니다.
static <X, Y, Z> Map<X, Z> transform1(Map<? extends X, ? extends Y> input,
Function<Y, Z> function) {
Map<X, Z> result = new HashMap<>();
input.forEach((k, v) -> result.put(k, function.apply(v)));
return result;
}
Map.forEach()
스트림 대신 사용 합니다. 지도와 함께 사용하기가 다소 어수선한 수집가가 필요 없기 때문에 훨씬 간단합니다. 그 이유는 Map.forEach()
키와 값을 별도의 매개 변수로 제공하는 반면 스트림에는 하나의 값만 있으므로 키 또는 맵 항목을 해당 값으로 사용할지 여부를 선택해야하기 때문입니다. 마이너스 측면에서는 다른 접근 방식의 풍부하고 유선형의 장점이 부족합니다. 🙂
답변
이와 같은 일반적인 솔루션
public static <X, Y, Z> Map<X, Z> transform(Map<X, Y> input,
Function<Y, Z> function) {
return input
.entrySet()
.stream()
.collect(
Collectors.toMap((entry) -> entry.getKey(),
(entry) -> function.apply(entry.getValue())));
}
예
Map<String, String> input = new HashMap<String, String>();
input.put("string1", "42");
input.put("string2", "41");
Map<String, Integer> output = transform(input,
(val) -> Integer.parseInt(val));
답변
구아바의 기능 Maps.transformValues
은 당신이 찾고있는 것이며 람다 식과 잘 작동합니다.
Maps.transformValues(originalMap, val -> ...)
답변
100 % 기능적이고 유창해야합니까? 그렇지 않은 경우이 정도는 얼마입니까?
Map<String, Integer> output = new HashMap<>();
input.forEach((k, v) -> output.put(k, Integer.valueOf(v));
( 스트림과 부작용을 결합하는 부끄러움과 죄책감으로 살 수 있다면 )
답변
표준 스트림 API를 향상시키는 My StreamEx 라이브러리는 EntryStream
맵 변환에 더 적합한 클래스를 제공합니다 .
Map<String, Integer> output = EntryStream.of(input).mapValues(Integer::valueOf).toMap();
답변
학습 목적으로 항상 존재하는 대안은 toMap () JDK 수집기가 간결 (+1 여기 ) 이지만 Collector.of ()를 통해 사용자 정의 수집기를 작성하는 것입니다 .
Map<String,Integer> newMap = givenMap.
entrySet().
stream().collect(Collector.of
( ()-> new HashMap<String,Integer>(),
(mutableMap,entryItem)-> mutableMap.put(entryItem.getKey(),Integer.parseInt(entryItem.getValue())),
(map1,map2)->{ map1.putAll(map2); return map1;}
));