문제 개요
점(.)으로 구분된 문자열 배열을 입력받아, 각 문자열의 계층 구조를 그대로 반영하는 객체를 반환하는 자바스크립트 함수를 작성해야 합니다.
예를 들어, 다음과 같은 배열이 있다고 가정해 보겠습니다.
const arr = [
"country.UK.level.1",
"country.UK.level.2",
"country.US.level.1",
"country.UK.level.3"
];이 배열을 변환하면 아래와 같은 형태의 결과가 나와야 합니다.
const output = {
"country": [
{"UK" : {"level" : ["1", "2", "3"]}},
{"US" : {"level" : ["1","2"]}}
]
}조건
- 배열에 저장된 문자열은 정렬되어 있지 않으며, 코드는 정렬 여부와 관계없이 안정적으로 동작해야 합니다.
- 문자열은 x.y.x.y... 패턴을 따릅니다. 여기서 x 위치(country, level)는 항상 고정되고, y 위치(UK, US, 1, 2 등)는 달라질 수 있습니다.
- 문자열의 길이에는 제한이 없습니다. 문자열이 길어질수록 객체의 중첩 깊이도 깊어지므로, 재귀적 또는 반복적인 순회 방식으로 처리해야 합니다.
구현 코드
다음은 위 조건을 만족하는 전체 코드입니다.
const arr = [
"country.UK.level.1",
"country.UK.level.2",
"country.US.level.1",
"country.UK.level.3"
];
const stringToObject = arr => {
const obj = {};
arr.forEach(str => {
let curr = obj;
let splitted = str.split('.');
let last = splitted.pop();
let beforeLast = splitted.pop();
splitted.forEach( sub => {
if(!curr.hasOwnProperty(sub)){
curr[sub] = {};
};
curr = curr[sub];
});
if(!curr[beforeLast]){
curr[beforeLast] = [];
};
curr[beforeLast].push(last);
});
return obj;
};
console.log(JSON.stringify(stringToObject(arr), undefined, 4));코드 동작 원리
이 코드의 핵심 로직은 다음과 같이 단계별로 이해할 수 있습니다.
- 문자열 분리: split('.') 메서드로 각 문자열을 점 기준으로 나눕니다. 예를 들어 "country.UK.level.1"은 ["country", "UK", "level", "1"]이 됩니다.
- 마지막 두 요소 추출: pop()을 두 번 호출하여 마지막 값(1)과 그 바로 앞 키(level)를 분리합니다.
- 중간 경로 생성: 남은 요소들(country, UK)을 순회하면서 hasOwnProperty로 기존 키 존재 여부를 확인하고, 없으면 빈 객체({})를 새로 만듭니다. 이 과정에서 참조 변수 curr가 한 단계씩 깊숙이 이동합니다.
- 값 저장: 최종 위치에서 beforeLast(level) 키에 배열이 없으면 새 배열을 초기화한 뒤, last(1) 값을 push합니다.
이 방식 덕분에 문자열이 몇 단계로 구성되어 있더라도 동일한 로직으로 처리할 수 있으며, 이미 존재하는 경로는 중복 생성하지 않으므로 정렬되지 않은 입력에도 문제없이 동작합니다.
실행 결과
위 코드를 실행하면 콘솔에 다음과 같은 출력이 나타납니다.
{
"country": {
"UK": {
"level": [
"1",
"2",
"3"
]
},
"US": {
"level": [
"1"
]
}
}
}결과를 보면 country 아래에 UK와 US가 각각 객체로 배치되고, 각 국가의 level 키에는 해당하는 레벨 값들이 배열로 수집된 것을 확인할 수 있습니다. UK에는 1, 2, 3이 모두 포함되지만, US에는 입력 데이터에 1만 존재하므로 1만 담기게 됩니다.