[Section2] 02. 자료구조와 알고리즘 기초 - 재귀 / 20230511

2023. 5. 11. 23:48

🧑🏻‍💻 TIL(Today I Learned)


✔️ StringifyJSON 과제

 

JSON이란? 

➡️ JavaScript Object Notation의 줄임말, 데이터 교환을 위해 만들어진 객체 형태의 포맷 
    : 서로 다른 프로그램 사이에서 데이터를 교환하기 위한 포맷 (자바스크립트를 포함한 많은 언어에서 범용적으로 사용)
➡️ JSON으로 변환된 객체의 타입은 문자열

➡️ 오늘은 jackson 라이브러리에서 제공하는 ObjectMapper 클래스를 사용하여 JSON 형태로 변경하는 방법을 배움 

📍 Jackson 라이브러리?
→ JSON 데이터 구조를 처리해주는 라이브러리 
Map<String, String> message = new HashMap<>(){{
      put("sender", "김코딩");
      put("receiver", "박해커");
      put("message", "밥먹을래?");
      put("createdAt", "2021-01-12,10:10:10");
    }};
  • 메세지를 담고 있는 데이터 
    → 데이터가 전송되려면 메세지를 보내는 발신자와 메세지를 받는 수신자가 같은 프로그램을 사용하거나 문자열처럼 범용적으로 읽을 수 있는 형태여야 함 
ObjectMapper mapper = new ObjectMapper();
String json = mapper.writeValueAsString(message);

System.out.println(json);
/*
{"createdAt":"2021-01-12,10:10:10","receiver":"박해커","sender":"김코딩","message":"밥먹을래?"}
*/

// writeValueAsStsring 하는 과정을 '직렬화(serialize)'라고 함
  • 발신자는 객체를 직렬화한 문자열을 누군가에게 보낼 수 있음, 수신자가 문자열 메세지를 다시 객체의 형태로 만들기 위해서는 
ObjectMapper mapper = new ObjectMapper();
String json = "{\"createdAt\":\"2021-01-12,10:10:10\",\"receiver\":\"박해커\",\"sender\":\"김코딩\",\"message\":\"밥먹을래?\"}";

Map<String, String> deserializedData = mapper.readValue(json, Map.class);
System.out.println(deserializedData);
/*
{createdAt=2021-01-12,10:10:10, receiver=박해커, sender=김코딩, message=밥먹을래?}
*/
  • 직렬화된 JSON에 readValue 적용하면 다시 객체의 형태로 변환할 수 있음 
    → readValue 적용하는 과정을 역직렬화(deserialize)라고 함
📍 이스케이프 문자(escape sequence)? 
: 문자열 내에서 특수한 기능을 사용하는 문자
  위 코드를 보면 아래와 같은 직렬화한 문자열을 볼 수 있는데 글자 사이사이에 역슬래시(\) 가 있음 
"{\"createdAt\":\"2021-01-12,10:10:10\",\"receiver\":\"박해커\",\"sender\":\"김코딩\",\"message\":\"밥먹을래?\"}";
\" 글자 앞뒤로 이렇게 써주면 쌍따옴표를 포함해서 출력하겠다는 의미 (\"createdAt\")
→ 전체적인 문자열과 그 안에서 쌍따옴표를 포함해서 출력하겠다는 것을 구분하는 역할이라고 할 수 있음 
    "string" / "\"string\""

  •  결과가 아래와 같이 나오는 것을 확인할 수 있음

 

🔎  JSON의 기본 규칙

➡️ 키 : 반드시 쌍따옴표를 붙여야 함 

➡️ 문자열 값 : 반드시 쌍따옴표로 감싸야 함 

➡️ 키와 값 사이, 그리고 키-값 쌍 사이에는 공백이 있어서는 안 됨

 

 


✔️ 재귀를 이용해 메서드 stringify 구현하기 

➡️ 위에서 얘기했던  writeValue 메서드를 함수의 형태로 직접 구현하기 위해 재귀 사용하기 

➡️ JSON은 대표적인 트리 구조, 전형적인 재귀 탐색이 가능한 구조(객체의 값으로 객체를 포함하는 구조) 

 

👉🏻 입력된 값이 문자열일 경우

if(data instanceof String) {
	return String.format("\"%s\"", data); //JSON 형식으로 출력하기 위한
 }

👉🏻 입력된 값이 Integer일 경우

if(data instanceof Integer) {
	return Integer.toString((Integer)data); // 명시적으로 타입 변환을 써주는 것이 좋음 
}

 

👉🏻 입력된 값이 Boolean일 경우

if(data instanceof boolean) {
	return String.valueOf(data); // 매개변수로 전달된 값을 문자열로 변환하는 역할
}

 

👉🏻 입력된 값이 Object[]일 경우

// 제일 처음 봐야할 것은 Object[] 타입이라는 것 결국은 모든 타입이 들어올 수 있음
// [1, 2, 3]
// [1, 2, true]
// [1,"true", true]
// 이런 식으로 어떻게 다양하게 나올지 모름 

if(data instanceof Object[]) {
	HashMap tmp = (HashMap)data;
    String str = "";
    
    Set<Map.Entry<Object, Object>> set = tmp.entrySet();
    Iterator<Map.Entry<Object, Objectt> entryIterator = set.iterator();
    while(entryIterator.hasNext()) {
    	Map.Entry<Object, Object> entry = entryIterator.next();
        Object key = entry.getKey();
        Object value = entry.getValue();
        
        str += String.format("%s:%s", stringify(key), stringify(value)) + ",";
	}
    String result = str.substring(0, str.length()- 1);
    System.out.println(String.format("{%s}", result));
if(data instanceof Object[]) {
	
    for(int i = 0; i < tmp.length; i++) {
    	tmp[i] = stringify(tmp[i]);
    }
    return Arrays.toString(tmp).replaceAll(" ", "").replaceAll("=", ":");
 }
 // 문제 자체가 완벽한 JSON 과는 좀 다르기 때문에 약간의 차이는 존재함
 // 이해가 안 갈 때는 손파일링(?)으로 직접 넣어주자!
 
// 만약 [1, 2, 3] 이 data로 들어왔다고 한다면 
if([1, 2, 3] instancof Object[]) {
	for(int i = 0; i < tmp.length; i++) {
    	tmp[0] = stringify(1); 
        // 그럼 이 stringify(1)은 data == 0
        // 즉, Integer 타입을 변환하는 경우의 조건에 걸려서 "" 이런 식으로 바뀌어서 들어감 
        // tmp[0] = 1;
        
        tmp[1] = stringify(2);
        tmp[2] = stringify(3);
        // 이런 식으로 반복하면서 tmp에 문자열로 된 배열이 할당됨 
        // 그리고 Array.toString(tmp) 사용하여 문자열로 출력 
        // replaceAll() 메서드는 JSON은 띄어쓰기가 허용되지 않기 때문에 붙여쓰도록 해줌 
   }

👉🏻 입력된 값이 HashMap일 경우

if(data instanceof HashMap) {
      HashMap tmp = (HashMap)data;

      String str = "";
      Set<Map.Entry<Object, Object>> set = tmp.entrySet();
      Iterator<Map.Entry<Object, Object>> entryIterator = set.iterator();
      while(entryIterator.hasNext()) { // 반복자 통해서 키와 값 꺼내기 
        Map.Entry<Object, Object> entry = entryIterator.next();
        Object key = entry.getKey();
        Object value = entry.getValue();

        str += String.format("%s:%s", stringify(key), stringify(value))+"," ;
      }
      String result = str.substring(0, str.length() - 1);
      System.out.println(String.format("{%s}",result));
    }
// HashMap은 순서가 없음 --> 하지만 데이터를 입력받은 순서대로 JSON 변환해서 나타내야 해!
// 그렇다면 결과를 받을 새로운 타입의 객체 생성하기 --> LinkedHashMap

HashMap<Object, Object> map = (HashMap<Object, Object>)data;
HashMap<Object,Object> result = new LinkedHashMap<>();

for(Map.Entry<Object, Object> entry : map.entrySet()) {
	String key = stringify(entry.getKey());
    String value = stringify(entry.getValue());
    result.put(key, value);
    }
    return result.toString().replaceAll(" ","");
}

👉🏻 입력된 값이 null일 경우

return ObjectMapper(null);

 


오늘도 역시나 쉽지 않은 하루였다...... 페어 분이 아니었다면 하루 종일 삽질하고 있었을 듯 재귀 쉽지 않다. 아직은 생각의 깊이가 깊지 않아서 생각을 하고 적용을 해보는 게 많이 어렵다. 꾸준히 하다보면 익숙해지겠지만 과정은 늘 괴롭다. 코치님이랑 할 때는 이해가 가는데 혼자서 하면 또 어리둥절하는 부분도 많다. 몇 번이고 반복하고 반복해야지...... 😇

BELATED ARTICLES

more