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

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

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


Java(자바)

Java Map 다양한 데이터 정렬하기(자바 맵 정렬 - 2)

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

Java에서 Map에 대한 단순한 데이터 정렬은 매우 쉽습니다.

{
    HashMap<Object, Object> item = new HashMap<>();
    item.put("Abcd", 123);
    item.put("ared", 52);
    item.put("qred", 456);

    Comparator order = Comparators.comparable().reversed();
    Comparator compare =  Map.Entry.comparingByValue(order);
    item.entrySet().stream().sorted(compare).forEach(System.out::println);
}

 

위 내용은 값을 대상으로 정렬를 하는 모습입니다.

Object를 키와 값으로 정렬을 하려면 제네릭을 생략해야되는 단점이 발생합니다.

값이 잘 나오네요~

 

그런데 대부분의 데이터들이 이처럼 단순하게 key와 value로 이루어서 나오지 않습니다.

예를 들어, Map 객체에 Map 객체가 있는 경우를 살펴보겠습니다.

{
    HashMap<Object, Object> json = new HashMap<>();

    HashMap<Object, Object> mini1 = new HashMap<>();
    mini1.put("power", 2031);
    mini1.put("beautiful", 10);

    HashMap<Object, Object> mini2 = new HashMap<>();
    mini2.put("power", 1000);
    mini2.put("beautiful", 200);

    HashMap<Object, Object> child = new HashMap<>();
    child.put("power", 10);
    child.put("beautiful", 20);

    json.put("man", mini1);
    json.put("woman", mini2);
    json.put("child", child);
}

 

마치 json처럼 Map 객체 1개에 3개의 Map 객체가 저장되어 있습니다.

위 방법으로 하면 당연히 정렬이 되지 않으므로 Comparator에 내장된 comparing 메소드를 사용하여야 합니다.

Comparator는 인터페이스의 일종이지만 static 한 메소드인 comparing메소드를 가지고 있습니다.

* 위 예제는 Comparators 입니다!  Comparators는 추상 클래스 입니다.

{
    HashMap<Object, Object> json = new HashMap<>();

    HashMap<Object, Object> mini1 = new HashMap<>();
    mini1.put("power", 2031);
    mini1.put("beautiful", 10);

    HashMap<Object, Object> mini2 = new HashMap<>();
    mini2.put("power", 1000);
    mini2.put("beautiful", 200);

    HashMap<Object, Object> child = new HashMap<>();
    child.put("power", 10);
    child.put("beautiful", 20);

    json.put("man", mini1);
    json.put("woman", mini2);
    json.put("child", child);
    
    //맵 안의 맵 객체의 key 값인 power를 기준으로 정렬합니다.
    //comparing 메소드 내부의 함수에 HashMap<Object,Object>를 지정하여 주었습니다.
    Comparator<HashMap<Object, Object>> inner = Comparator.comparing( (HashMap<Object,Object> arg)-> {
    		return Integer.parseInt(arg.get("power").toString());
    });    
}

 

첫번째 단계로 비교할 행위를 만들어 줍니다.

Map에 Map이 담긴 형태이므로 comparing메소드에 함수로 Map객체를 넣어준 뒤에 정렬할 대상 값을 리턴하였습니다.

다음으로는 첫번째 예제와 동일하게 값을 정렬하는 것 입니다.

{
    HashMap<Object, Object> json = new HashMap<>();

    HashMap<Object, Object> mini1 = new HashMap<>();
    mini1.put("power", 2031);
    mini1.put("beautiful", 10);

    HashMap<Object, Object> mini2 = new HashMap<>();
    mini2.put("power", 1000);
    mini2.put("beautiful", 200);

    HashMap<Object, Object> child = new HashMap<>();
    child.put("power", 10);
    child.put("beautiful", 20);

    json.put("man", mini1);
    json.put("woman", mini2);
    json.put("child", child);
    
    //맵 안의 맵 객체의 key 값인 power를 기준으로 정렬합니다.
    //comparing 메소드 내부의 함수에 HashMap<Object,Object>를 지정하여 주었습니다.
    Comparator<HashMap<Object, Object>> inner = Comparator.comparing( (HashMap<Object,Object> arg)-> {
    		return Integer.parseInt(arg.get("power").toString());
    });    
    Comparator compare = Map.Entry.comparingByValue(inner);
    json.entrySet().stream().sorted(compare).collect(Collectors.toList());  //정렬!
}

 

inner를 통해서 내부의 Map이 정렬된 내용을 Map.Entry.comparingByValue에 넣어주었습니다.

다음으로 이제는 stream 객체를 통해서 정렬을 한 뒤에 결과를 받으면 끝 입니다!

에..에러?

 

 

우리는 해당 대상이 어떠한 자료형태인지 알 고 있습니다.

그런데 Java는 Comparator의 제네릭을 완성하지 않았으므로 위 내용처럼 빨강색 오류가 나타나게 됩니다.

Object로 이루어진 Map정렬은 이러한 단점을 가지고 있습니다.

그러면 캐스팅을 통해서 문제를 해결하여 줍니다.

{
    HashMap<Object, Object> json = new HashMap<>();

    HashMap<Object, Object> mini1 = new HashMap<>();
    mini1.put("power", 2031);
    mini1.put("beautiful", 10);

    HashMap<Object, Object> mini2 = new HashMap<>();
    mini2.put("power", 1000);
    mini2.put("beautiful", 200);

    HashMap<Object, Object> child = new HashMap<>();
    child.put("power", 10);
    child.put("beautiful", 20);

    json.put("man", mini1);
    json.put("woman", mini2);
    json.put("child", child);
    
    //맵 안의 맵 객체의 key 값인 power를 기준으로 정렬합니다.
    //comparing 메소드 내부의 함수에 HashMap<Object,Object>를 지정하여 주었습니다.
    Comparator<HashMap<Object, Object>> inner = Comparator.comparing( (HashMap<Object,Object> arg)-> {
    		return Integer.parseInt(arg.get("power").toString());
    });    
    Comparator compare = Map.Entry.comparingByValue(inner);
    List<Object> list = (List<Object>)json.entrySet().stream().sorted(compare).collect(Collectors.toList());
    list.forEach(System.out::println);
}

노랑색 경고가 찝찝하지만 그래도 결과는 잘 나왔습니다.

 

stream 객체에서 collector를 통하여 list로 결과를 받았습니다.

이처럼 Object형태의 Map 정렬은 제네릭 문제로 인하여 계속해서 오류를 만나게 됩니다.

만약 해당 데이터를 Map형태로 다시 가공하려면 아래처럼 바꾸어야 합니다.

{
    HashMap<Object, Object> json = new HashMap<>();

    HashMap<Object, Object> mini1 = new HashMap<>();
    mini1.put("power", 2031);
    mini1.put("beautiful", 10);

    HashMap<Object, Object> mini2 = new HashMap<>();
    mini2.put("power", 1000);
    mini2.put("beautiful", 200);

    HashMap<Object, Object> child = new HashMap<>();
    child.put("power", 10);
    child.put("beautiful", 20);

    json.put("man", mini1);
    json.put("woman", mini2);
    json.put("child", child);
    
    //맵 안의 맵 객체의 key 값인 power를 기준으로 정렬합니다.
    //comparing 메소드 내부의 함수에 HashMap<Object,Object>를 지정하여 주었습니다.
    Comparator<HashMap<Object, Object>> inner = Comparator.comparing( (HashMap<Object,Object> arg)-> {
    		return Integer.parseInt(arg.get("power").toString());
    });    
    Comparator compare = Map.Entry.comparingByValue(inner);
    HashMap<Object, Object> reMap = (HashMap<Object, Object>) json.entrySet().stream().sorted(compare).collect(
    Collectors.toMap( key -> {
            Map.Entry set = (Map.Entry) key;   //HashMap$Node
            return set.getKey();					
        }, value ->  {
            Map.Entry set = (Map.Entry) value;   //HashMap$Node
            return set.getValue();					
        },
        (oldValue, newValue) -> oldValue,
        LinkedHashMap::new
        )
    );
    reMap.forEach( (k,v) ->{
        System.out.println(k + " : " + v);
    });    
}

 

Object의 형태의 모습에 의해서 노랑색 경고가 계속해서 타나납니다..ㅠ

그래도 결과는 만족스럽게 나나탑니다.

노랑색 경고!

 

만약 Map 객체가 value가 List이면서 Map을 포함하고 있다면 위 내용과 비슷한 방식으로 작업하면 됩니다.

아래 샘플 데이터를 먼저 생성하였습니다.

{
    HashMap<Object, Object> json = new HashMap<>();
    
    //데이터를 생성하였습니다. List형식에 Map 데이터를 가지고 있습니다.
    Arrays.asList(1,2,3).forEach( num->{
        List<HashMap<Object, Object>> list = new ArrayList<HashMap<Object,Object>>();
        HashMap<Object, Object> item = new HashMap<>();
        item.put("number", num);
        item.put("text", "text_"+num);
        list.add(item);

        item = new HashMap<>();
        item.put("number_multi", num * 2);
        list.add(item);

        json.put("data_" + num, list);
    });
}

 

역시 위 데이터도 Comparators 추상 클래스가 아니라 Comparator의 static 메소드를 사용해서 정렬을 구현하여 주도록 합니다.

여기서는 배열의 첫번째 number값을 기준으로 정렬하여 보았습니다.

{
    HashMap<Object, Object> json = new HashMap<>();
    
    //데이터를 생성하였습니다. List형식에 Map 데이터를 가지고 있습니다.
    Arrays.asList(1,2,3).forEach( num->{
        List<HashMap<Object, Object>> list = new ArrayList<HashMap<Object,Object>>();
        HashMap<Object, Object> item = new HashMap<>();
        item.put("number", num);
        item.put("text", "text_"+num);
        list.add(item);

        item = new HashMap<>();
        item.put("number_multi", num * 2);
        list.add(item);

        json.put("data_" + num, list);
    });

    //내부 정렬
    Comparator<List<HashMap<Object, Object>>> compare1 = Comparator.comparing( (List<HashMap<Object, Object>>  arg)-> {
        if(arg.get(0) == null) {
            return 0;
        }
        String parsing = Optional.ofNullable(arg.get(0).get("number")).orElse("0").toString();
        return Integer.parseInt(parsing);
    });
    
    //value로 정렬 지정
    Comparator compare2 = Map.Entry.comparingByValue(compare1);
    List<Object> list = (List<Object>) json.entrySet().stream().sorted(compare2).collect(Collectors.toList());
    list.forEach(System.out::println);    
    
}

 

역시나 Object형식의 key와 value로 인하여 경고가 주어지고 있습니다.

이를 실행하여보면 데이터가 잘 정렬되는 것을 볼 수 있습니다.

정렬되었습니다.

 

Map을 대상으로 정렬하는 것은 Comparators 클래스를 사용하느냐, Comparator 인터페이스를 사용하느냐로 구분되어 집니다.

복잡한 데이터 형식이 아니라면 Comparators 클래스를 주로 사용하게되며, (자바 기본 자료형)

Map이나 List처럼 컬렉션이나 vo객체(value of Object)를 대상으로 정렬하려면 Comparator 인터페이스를 사용합니다.

 

위 내용에 대한 전체 코드 입니다.

import java.util.ArrayList;
import java.util.Arrays;
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 MapWithComparatorStudy {
	
    public static void main(String[] args) {
        firstCase();		
        secondCase();
    }
    
    public static void firstCase(){
        HashMap<Object, Object> json = new HashMap<>();
		
        HashMap<Object, Object> mini1 = new HashMap<>();
        mini1.put("power", 2031);
        mini1.put("beautiful", 10);
		
        HashMap<Object, Object> mini2 = new HashMap<>();
        mini2.put("power", 1000);
        mini2.put("beautiful", 200);
		
        HashMap<Object, Object> child = new HashMap<>();
        child.put("power", 10);
        child.put("beautiful", 20);
		
        //위 데이터 넣어주기
        json.put("man", mini1);
        json.put("woman", mini2);
        json.put("child", child);

        Comparator<HashMap<Object, Object>> inner = Comparator.comparing( (HashMap<Object,Object> arg)-> {
            return Integer.parseInt(arg.get("power").toString());
        });
		
        Comparator compare = Map.Entry.comparingByValue(inner);
        List<Object> list = (List<Object>)json.entrySet().stream().sorted(compare).collect(Collectors.toList());
        list.forEach(System.out::println);
        
        //compare.reversed()  -> 역순
//      List<Object> list = (List<Object>) json.entrySet().stream().sorted(compare).collect(Collectors.toList());
//      list.forEach(System.out::println);
//		
        HashMap<Object, Object> reMap = (HashMap<Object, Object>) json.entrySet().stream().sorted(compare).collect(
            Collectors.toMap( (Map.Entry key) -> {
                Map.Entry set =  key;   //HashMap$Node
                return set.getKey();					
            }, value ->  {
                Map.Entry set = (Map.Entry) value;   //HashMap$Node
                return set.getValue();					
            },
            (oldValue, newValue) -> oldValue,
            LinkedHashMap::new  //Linked로 하지 않으면 정렬이 풀립니다!
            )
        );
        reMap.forEach( (k,v) ->{
            System.out.println(k + " : " + v);
        });
    }
	
    public static void secondCase(){
        HashMap<Object, Object> json = new HashMap<>();
        Arrays.asList(1,2,3).forEach( num->{
            List<HashMap<Object, Object>> list = new ArrayList<HashMap<Object,Object>>();
            HashMap<Object, Object> item = new HashMap<>();
            item.put("number", num);
            item.put("text", "text_"+num);
            list.add(item);
			
            item = new HashMap<>();
            item.put("number_multi", num * 2);
            list.add(item);
			
            json.put("data_" + num, list);
        });
    		
        Comparator<List<HashMap<Object, Object>>> compare1 = Comparator.comparing( (List<HashMap<Object, Object>>  arg)-> {
            if(arg.get(0) == null) {
                return 0;
            }
            String parsing = Optional.ofNullable(arg.get(0).get("number")).orElse("0").toString();
            return Integer.parseInt(parsing);
        });
        Comparator compare2 = Map.Entry.comparingByValue(compare1);
        List<Object> list = (List<Object>) json.entrySet().stream().sorted(compare2).collect(Collectors.toList());
        list.forEach(System.out::println);		
    }
}

 

허접하지만 나름 내용을 정리하면서 Map객체에 대한 내용을 많이 찾고 확인할 수 있었던 것 같았습니다.

궁금한점이나 틀린점은 언제든지 연락주세요!

 

* Java Map 정렬과 관련된 이전글 입니다.

lts0606.tistory.com/358

 

Java Map 정렬하기(자바 맵 정렬)

Java버전이 8이상으로 올라오면서 컬렉션에 대한 자료처리하는 다양한 함수들이 생겨났습니다. 힘들게 만들었던 알고리즘과 각종 메소드를 통해 하였던 작업이 이제는 손쉽게 만들 수 있게 되었

lts0606.tistory.com

* Java sort map list, Java Map List 정렬, Java sort Map Map, Java sort HashMap, Java sort HashMap List

 

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

댓글