대시(-)로 구분된 반복 단어들이 포함된 문자열이 다음과 같이 주어졌다고 가정해 보겠습니다.
const str = 'monday-sunday-tuesday-tuesday-sunday-sunday-monday-mondaymonday';
우리의 과제는 각 객체가 value와 count라는 두 개의 속성을 가진 객체 배열을 반환하는 함수를 작성하는 것입니다. 여기서 value는 문자열에 포함된 단어(monday, tuesday, sunday)를 의미하며, count는 해당 단어가 연속으로 나타난 횟수를 나타냅니다.
예를 들어 위 문자열의 경우 결과 배열은 다음과 같은 형태가 됩니다.
const arr = [{
val: 'monday',
count: 1
}, {
val: 'sunday',
count: 1
}, {
val: 'tuesday',
count: 2
}, {
val: 'sunday',
count: 2
}, {
val: 'monday',
count: 3
}]그 이유는 monday가 한 번, sunday가 한 번, tuesday가 두 번, sunday가 두 번, 마지막으로 monday가 세 번 연속으로 나타나기 때문입니다.
해결 접근 방식
먼저 문자열을 대시(-) 기준으로 분할한 뒤, Array.prototype.reduce() 메서드를 활용하여 원하는 형태의 배열을 순차적으로 만들어낼 수 있습니다.
전체 코드는 다음과 같습니다.
예제 코드
const str = 'monday-sunday-tuesday-tuesday-sunday-sunday-monday-mondaymonday';
const str2 = 'friday-friday-sunday-tuesday-sunday-sunday-monday-thursdaymonday';
const compressString = (str) => {
return str.split('-').reduce((acc, val) => {
const { length: l } = acc;
if(acc[l-1]?.val === val){
acc[l-1].count++;
return acc;
}else{
return acc.concat({
val,
count: 1
});
}
}, []);
}
console.log(compressString(str));
console.log(compressString(str2));코드 동작 원리
이 코드의 핵심 로직을 단계별로 살펴보면 다음과 같습니다.
- split('-'): 문자열을 대시 기준으로 분리하여 단어 배열을 생성합니다.
- reduce(): 각 단어를 순회하면서 누적 배열(acc)의 마지막 요소와 현재 단어를 비교합니다.
- 옵셔널 체이닝(?): 배열이 비어 있는 초기 상태에서 발생할 수 있는 오류를 안전하게 처리합니다.
- 마지막 요소의 값이 현재 단어와 같으면 count를 1 증가시키고, 다르면 새로운 객체를 배열에 추가합니다.
이러한 방식은 시간 복잡도 O(n)으로 한 번의 순회만으로 연속 요소를 효율적으로 그룹화할 수 있다는 장점이 있습니다.
실행 결과
위 코드를 실행하면 콘솔에 다음과 같은 결과가 출력됩니다.
[
{ val: 'monday', count: 1 },
{ val: 'sunday', count: 1 },
{ val: 'tuesday', count: 2 },
{ val: 'sunday', count: 2 },
{ val: 'monday', count: 3 }
]
[
{ val: 'friday', count: 2 },
{ val: 'sunday', count: 1 },
{ val: 'tuesday', count: 1 },
{ val: 'sunday', count: 2 },
{ val: 'monday', count: 1 },
{ val: 'thursday', count: 1 },
{ val: 'monday', count: 1 }
]