문제 상황
다음과 같은 구절(phrase)들로 이루어진 참조 배열이 있다고 가정해 보겠습니다.
const reference = ["your", "majesty", "they", "are", "ready"];
그리고 위 배열의 일부 요소들을 또 다른 배열을 기준으로 병합해야 하는 상황입니다. 기준이 되는 배열은 다음과 같습니다.
const another = ["your", "they are"];
원하는 최종 결과는 다음과 같습니다.
result = ["your", "majesty", "they are", "ready"];
즉, 두 배열의 요소를 서로 비교하여, 첫 번째 배열에서 연속된 요소들이 두 번째 배열에 하나의 문자열로 존재하면 해당 요소들을 하나로 합치는 것입니다.
따라서 우리는 이러한 두 개의 배열을 입력받아 병합된 새로운 배열을 반환하는 JavaScript 함수를 작성해야 합니다.
구현 방법
이 문제는 다음과 같은 순서로 해결할 수 있습니다.
- another 배열에서 공백을 포함한 요소, 즉 여러 단어로 이루어진 항목만 필터링합니다.
- 필터링된 각 항목에 대해 reference 배열의 앞부분부터 동일한 단어 수만큼 잘라내어 비교합니다.
- 일치하면 해당 구간을 하나의 문자열로 결과 배열에 추가하고, 일치하지 않으면 reference의 첫 번째 요소를 결과 배열로 옮깁니다.
- 모든 병합 작업이 끝나면 reference에 남아 있는 나머지 요소들을 결과 뒤에 붙여 반환합니다.
예제 코드
const reference = ["your", "majesty", "they", "are", "ready"];
const another = ["your", "they are"];
const joinByReference = (reference = [], another = []) => {
const res = [];
const filtered = another.filter(a => a.split(" ").length > 1);
while(filtered.length) {
let anoWords = filtered.shift();
let len = anoWords.split(" ").length;
while(reference.length > len) {
let refWords = reference.slice(0, len).join(" ");
if (refWords == anoWords) {
res.push(refWords);
reference = reference.slice(len, reference.length);
break;
};
res.push(reference.shift());
};
};
return [...res, ...reference];
};
console.log(joinByReference(reference, another));
동작 원리
- 필터링 단계: another 배열에서 공백으로 구분된 단어가 2개 이상인 요소만 추출합니다. 이 예제에서는 단일 단어인 "your"는 제외되고 "they are"만 남습니다.
- 비교 및 병합 단계: "they are"은 2단어이므로 reference 배열의 앞에서부터 2개씩 묶어 비교합니다. "your majesty"는 일치하지 않으므로 "your"를 결과 배열로 이동시키고, 이어서 "majesty they" 역시 일치하지 않으므로 "majesty"를 이동시킵니다. 그다음 "they are"이 정확히 일치하므로 두 요소를 하나로 합쳐 결과에 넣습니다.
- 마무리 단계: 모든 병합 작업이 완료된 후 reference에 남아 있는 요소("ready")를 결과 배열 뒤에 붙여 최종 배열을 반환합니다.
출력 결과
위 코드를 실행하면 다음과 같은 출력이 생성됩니다.
[ 'your', 'majesty', 'they are', 'ready' ]