[java] Java 8에서 람다를 사용하여 Map <K, V>를 다른 Map <K, V>로 어떻게 변환합니까?

방금 Java 8을 살펴보기 시작했고 람다를 시험해보기 위해 최근에 작성한 아주 간단한 것을 다시 작성하려고 생각했습니다. 새 맵의 열이 첫 번째 맵의 열에 대한 방어 적 사본 인 문자열에서 열로의 맵을 다른 문자열에서 열로의 맵으로 바꿔야합니다. 열에 복사 생성자가 있습니다. 내가 지금까지 가장 가까운 것은 다음과 같습니다.

    Map<String, Column> newColumnMap= new HashMap<>();
    originalColumnMap.entrySet().stream().forEach(x -> newColumnMap.put(x.getKey(), new Column(x.getValue())));

그러나 더 좋은 방법이 있어야한다고 확신하며 조언을 해 주셔서 감사합니다.



답변

수집기를 사용할 수 있습니다 .

import java.util.*;
import java.util.stream.Collectors;

public class Defensive {

  public static void main(String[] args) {
    Map<String, Column> original = new HashMap<>();
    original.put("foo", new Column());
    original.put("bar", new Column());

    Map<String, Column> copy = original.entrySet()
        .stream()
        .collect(Collectors.toMap(Map.Entry::getKey,
                                  e -> new Column(e.getValue())));

    System.out.println(original);
    System.out.println(copy);
  }

  static class Column {
    public Column() {}
    public Column(Column c) {}
  }
}


답변

Map<String, Integer> map = new HashMap<>();
map.put("test1", 1);
map.put("test2", 2);

Map<String, Integer> map2 = new HashMap<>();
map.forEach(map2::put);

System.out.println("map: " + map);
System.out.println("map2: " + map2);
// Output:
// map:  {test2=2, test1=1}
// map2: {test2=2, test1=1}

forEach방법을 사용하여 원하는 것을 수행 할 수 있습니다.

당신이하고있는 일은 :

map.forEach(new BiConsumer<String, Integer>() {
    @Override
    public void accept(String s, Integer integer) {
        map2.put(s, integer);
    }
});

우리는 람다로 단순화 할 수 있습니다 :

map.forEach((s, integer) ->  map2.put(s, integer));

그리고 우리는 단지 기존 메소드를 호출하기 때문에 메소드 reference를 사용할 수 있습니다 .

map.forEach(map2::put);


답변

HashMap.clone내부적으로 리해시를 수행 하기 때문에 모든 항목을 새 맵에 다시 삽입하지 않는 방법이 가장 빠릅니다 .

Map<String, Column> newColumnMap = originalColumnMap.clone();
newColumnMap.replaceAll((s, c) -> new Column(c));


답변

간단하게 유지하고 Java 8 :-를 사용하십시오.

 Map<String, AccountGroupMappingModel> mapAccountGroup=CustomerDAO.getAccountGroupMapping();
 Map<String, AccountGroupMappingModel> mapH2ToBydAccountGroups =
              mapAccountGroup.entrySet().stream()
                         .collect(Collectors.toMap(e->e.getValue().getH2AccountGroup(),
                                                   e ->e.getValue())
                                  );


답변

프로젝트에서 Guava (v11 최소)를 사용하는 경우 Maps :: transformValues를 사용할 수 있습니다 .

Map<String, Column> newColumnMap = Maps.transformValues(
  originalColumnMap,
  Column::new // equivalent to: x -> new Column(x) 
)

참고 :이 맵의 값은 느리게 평가됩니다. 변환 비용이 비싸면 Guava 문서에서 제안한 것과 같이 결과를 새 맵에 복사 할 수 있습니다.

To avoid lazy evaluation when the returned map doesn't need to be a view, copy the returned map into a new map of your choosing.


답변

다음은 일종의 변환을 수행해야하는 경우 키와 값에 동시에 액세스 할 수있는 또 다른 방법입니다.

Map<String, Integer> pointsByName = new HashMap<>();
Map<String, Integer> maxPointsByName = new HashMap<>();

Map<String, Double> gradesByName = pointsByName.entrySet().stream()
        .map(entry -> new AbstractMap.SimpleImmutableEntry<>(
                entry.getKey(), ((double) entry.getValue() /
                        maxPointsByName.get(entry.getKey())) * 100d))
        .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));


답변

타사 라이브러리를 사용하는 것이 마음에 들지 않으면 cyclops-react lib에 Map을 포함한 모든 JDK Collection 유형에 대한 확장이 있습니다 . map 또는 bimap 메소드를 직접 사용하여 맵을 변환 할 수 있습니다. MapX는 기존 Map으로 구성 할 수 있습니다.

  MapX<String, Column> y = MapX.fromMap(orgColumnMap)
                               .map(c->new Column(c.getValue());

키를 변경하려면 다음을 쓸 수 있습니다

  MapX<String, Column> y = MapX.fromMap(orgColumnMap)
                               .bimap(this::newKey,c->new Column(c.getValue());

bimap을 사용하여 키와 값을 동시에 변환 할 수 있습니다.

MapX가 Map을 확장함에 따라 생성 된 맵을 다음과 같이 정의 할 수도 있습니다.

  Map<String, Column> y