자바에서 List 객체를 Map으로 바꾸는 방법입니다.
자바8의 stream이 나오기 전 까지는 다양한 알고리즘과 방법으로 해당 작업을 하고는 했습니다.
아래처럼 코딩(?)하고는 했었습니다.
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class ListToMap {
public static void main(String[] args) {
List<String> list = new ArrayList<>();
list.add("aaaca");
list.add("aaa");
list.add("aaa");
list.add("bbbcccs");
list.add("ccc");
Map<String, Long> map = new HashMap<>();
for(String target : list){
Long num = map.get(target);
if(num == null){
map.put(target, 1l);
} else {
map.put(target, num+1);
}
}
System.out.println(map);
}
}
딱히 문제되 보이지 않는 코드입니다.
list를 반복문을 돌리면서 map에 담아두었고 map에 혹시 데이터가 있으면 숫자가 증가하는 구조 입니다.
위 내용을 자바8의 stream 객체를 활용하여 변경하여 보겠습니다.
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
public class ListToMap {
public static void main(String[] args) {
List<String> list = new ArrayList<>();
list.add("aaaca");
list.add("aaa");
list.add("aaa");
list.add("bbbcccs");
list.add("ccc");
/*Map<String, Integer> map = new HashMap<>();
for(String target : list){
Integer num = map.get(target);
if(num == null){
map.put(target, 1);
} else {
map.put(target, num+1);
}
}*/
map = list.stream()
.collect(Collectors.groupingBy( arg -> arg, HashMap::new, Collectors.counting()));
System.out.println(map);
}
}
정말 심플하게 바뀐것을 볼 수 있습니다.
해당 내용을 실행하여보면 아래와 같이 동일한 결과를 확인 할 수 있습니다.
stream에서 collect 메소드의 위력은 위 내용과 같이 단순한 List말고도 Map형태의 데이터를 담고 있는 대상에게도 적용 가능 합니다.
{
List<HashMap<Object, Object>> list2 = new ArrayList<>();
HashMap<Object, Object> a = new HashMap<Object, Object>();
a.put("key", "KA");
a.put("arg", 1234);
a.put("desc", "asdfsdaf");
list2.add(a);
a = new HashMap<Object, Object>();
a.put("key", "K");
a.put("arg", 675);
a.put("desc", "qreweraa");
list2.add(a);
a = new HashMap<Object, Object>();
a.put("key", "KA");
a.put("arg", 6745);
a.put("desc", "qAreweraa");
list2.add(a);
a = new HashMap<Object, Object>();
a.put("key", "KA");
a.put("arg", 32419);
a.put("desc", "qAreweraa");
list2.add(a);
}
list2라는 변수에 HashMap 데이터가 담겨져 있습니다.
해당 데이터에서 key라는 값을 지닌 대상으로 Map형태로 바꾸어 보겠습니다.
{
List<HashMap<Object, Object>> list2 = new ArrayList<>();
HashMap<Object, Object> a = new HashMap<Object, Object>();
a.put("key", "KA");
a.put("arg", 1234);
a.put("desc", "asdfsdaf");
list2.add(a);
a = new HashMap<Object, Object>();
a.put("key", "K");
a.put("arg", 675);
a.put("desc", "qreweraa");
list2.add(a);
a = new HashMap<Object, Object>();
a.put("key", "KA");
a.put("arg", 6745);
a.put("desc", "qAreweraa");
list2.add(a);
a = new HashMap<Object, Object>();
a.put("key", "KA");
a.put("arg", 32419);
a.put("desc", "qAreweraa");
list2.add(a);
LinkedHashMap<Object, List<HashMap<Object, Object>>> result = null;
result = list2.stream().collect( Collectors.groupingBy(arg-> arg.get("key"), LinkedHashMap::new, Collectors.toList()) );
result.forEach( (key, value)->{
System.out.println(key + " : " + value);
});
}
위 내용을 실행한 결과 입니다.
3번째 파라미터의 종류가 Collectors.toList() 라는 Collector 값이 들어왔기 때문에 list 형식으로 데이터가 들어간 것을 볼 수 있습니다.
만약 Collectors.toList()을 Collectors.counting()으로 바꾸어 주면 Long형태의 값이 들어가게 됩니다.
3번째 파라미터값으로 사용되는 Collectors 클래스에는 이처럼 Collector의 객체가 구현되어 있습니다.
Collector는 stream에서의 사용자가 할 작업의 형태가 담겨있다고 보시면 됩니다.
조금만 응용하여 보면 min, max등의 형태의 값으로 구분짓는 것도 가능합니다.
{
List<String> list = new ArrayList<>();
list.add("aaaca");
list.add("aaa");
list.add("aaa");
list.add("bbbcccs");
list.add("ccc");
Optional<String> maxStyle1 = list.stream().collect(Collectors.maxBy(Comparator.comparingInt(String::length)));
Optional<String> maxStyle2 =list.stream().max(Comparator.comparingInt(String::length));
System.out.println("maxStyle1 : "+maxStyle1.get());
System.out.println("maxStyle2 : "+maxStyle2.get());
Optional<String> minStyle1 = list.stream().collect(Collectors.minBy(Comparator.comparingInt(String::length)));
Optional<String> minStyle2 =list.stream().min(Comparator.comparingInt(String::length));
System.out.println("minStyle1 : "+minStyle1.get());
System.out.println("minStyle2 : "+minStyle2.get());
}
맨 처음 만들었던 list 변수를 통해서 min값과 max값을 가져오는 부분을 구현하여 보았습니다.
style1과 style2는 값을 가져오는 메소드의 형태가 조금 다를 뿐 내용은 같습니다.
각 기능별 필요한 함수를 직접 구현하여 사용한다면 나만의 groupby기능도 만드는데 문제 없을 것 같습니다.
위 소스코드의 전체 모습 입니다.
import java.util.ArrayList;
import java.util.Comparator;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.stream.Collectors;
public class ListToMap {
public static void main(String[] args) {
List<String> list = new ArrayList<>();
list.add("aaaca");
list.add("aaa");
list.add("aaa");
list.add("bbbcccs");
list.add("ccc");
Map<String, Long> map = new HashMap<>();
// Java8 이전에 사용하던 방법입니다.
for (String target : list) {
Long num = map.get(target);
if (num == null) {
map.put(target, 1l);
} else {
map.put(target, num + 1);
}
}
System.out.println(map);
// 리스트에서 map으로 바꾸는 방법 입니다.
map = list.stream().collect(Collectors.groupingBy(arg -> arg, HashMap::new, Collectors.counting()));
System.out.println(map);
//List에서 Map형태의 데이터가 있는 경우 입니다.
List<HashMap<Object, Object>> list2 = new ArrayList<>();
HashMap<Object, Object> a = new HashMap<Object, Object>();
a.put("key", "KA");
a.put("arg", 1234);
a.put("desc", "asdfsdaf");
list2.add(a);
a = new HashMap<Object, Object>();
a.put("key", "K");
a.put("arg", 675);
a.put("desc", "qreweraa");
list2.add(a);
a = new HashMap<Object, Object>();
a.put("key", "KA");
a.put("arg", 6745);
a.put("desc", "qAreweraa");
list2.add(a);
a = new HashMap<Object, Object>();
a.put("key", "KA");
a.put("arg", 32419);
a.put("desc", "qAreweraa");
list2.add(a);
//그룹한 데이터를 LIST로 담았습니다.
LinkedHashMap<Object, List<HashMap<Object, Object>>> result = null;
result = list2.stream()
.collect(Collectors.groupingBy(arg -> arg.get("key"), LinkedHashMap::new, Collectors.toList()));
result.forEach((key, value) -> {
System.out.println(key + " : " + value);
});
//그룹한 데이터를 갯수를 세어 Long형태로 넣었습니다.
list2.stream().collect(Collectors.groupingBy(arg -> arg.get("key"), LinkedHashMap::new, Collectors.counting()))
.forEach((key, value) -> {
System.out.println(key + "(count)" + " : " + value);
});
//간단하게 최소값, 최대값을 가져오는 부분 입니다.
Optional<String> maxStyle1 = list.stream().collect(Collectors.maxBy(Comparator.comparingInt(String::length)));
Optional<String> maxStyle2 = list.stream().max(Comparator.comparingInt(String::length));
System.out.println("maxStyle1 : " + maxStyle1.get());
System.out.println("maxStyle2 : " + maxStyle2.get());
Optional<String> minStyle1 = list.stream().collect(Collectors.minBy(Comparator.comparingInt(String::length)));
Optional<String> minStyle2 = list.stream().min(Comparator.comparingInt(String::length));
System.out.println("minStyle1 : " + minStyle1.get());
System.out.println("minStyle2 : " + minStyle2.get());
}
}
이상으로 List 데이터를 Map 형태로 바꾸는 방법에 대해 살펴보았습니다.
다양한 기능을 사용해 보기 위해서 컬렉션의 stream과 Collectors에 대해서 조금 더 살펴보아야 하겠습니다.
'Java(자바)' 카테고리의 다른 글
Javax mail 참조 및 수신기능이 되지 않을 때(Java cc, to not working) (0) | 2020.08.31 |
---|---|
Tomcat LifecycleMBeanBase Failed to unregister MBean with name(흔치 않는 톰캣 오류) (4) | 2020.07.08 |
Java Map 정렬하기(자바 맵 정렬) (0) | 2020.07.06 |
Java에서 Firebase 데이터 베이스 연동하기(안드로이드 없이, without Android) (8) | 2020.06.25 |
Java quartz synchronize (quartz 동기화, quartz 순서) (0) | 2020.05.26 |
댓글