본문 바로가기
블로그 이미지

방문해 주셔서 감사합니다! 항상 행복하세요!

  
   - 문의사항은 메일 또는 댓글로 언제든 연락주세요.
   - "해줘","답 내놔" 같은 질문은 답변드리지 않습니다.
   - 메일주소 : lts06069@naver.com


Java(자바)

Java List to Map (Java 리스트를 맵으로, 자바 List to Map)

야근없는 행복한 삶을 위해 ~
by 마샤와 곰 2020. 7. 6.

자바에서 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);
    });    
}

 

위 내용을 실행한 결과 입니다.

HashMap의 필드값인 "key"를 중심으로 그룹화 되었습니다.

 

3번째 파라미터의 종류가 Collectors.toList() 라는 Collector 값이 들어왔기 때문에 list 형식으로 데이터가 들어간 것을 볼 수 있습니다.

만약 Collectors.toList()을 Collectors.counting()으로 바꾸어 주면 Long형태의 값이 들어가게 됩니다.

요렇게 count를 해 주게 됩니다.

 

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에 대해서 조금 더 살펴보아야 하겠습니다.

 

반응형
* 위 에니메이션은 Html의 캔버스(canvas)기반으로 동작하는 기능 입니다. Html 캔버스 튜토리얼 도 한번 살펴보세요~ :)
* 직접 만든 Html 캔버스 애니메이션 도 한번 살펴보세요~ :)

댓글