JavaScript에서 두 개의 배열을 인자로 받는 함수 findPositions()를 작성해야 한다고 가정해 봅시다. 이 함수는 첫 번째 배열에 존재하는 두 번째 배열 요소들의 모든 인덱스를 배열 형태로 반환해야 합니다.
문제 예시
예를 들어 다음과 같은 배열이 있다고 해보겠습니다.
첫 번째 배열: ['john', 'doe', 'chris', 'snow', 'john', 'chris']
두 번째 배열: ['john', 'chris']
이 경우 출력 결과는 다음과 같아야 합니다.
[0, 2, 4, 5]
'john'은 인덱스 0과 4에 위치하고, 'chris'는 인덱스 2와 5에 위치하기 때문입니다. 그럼 이제 실제 코드를 작성해 보겠습니다.
forEach()를 활용한 해결 방법
이 문제는 forEach() 반복문을 사용하면 간단하게 해결할 수 있습니다. 첫 번째 배열을 순회하면서 각 요소가 두 번째 배열에 포함되어 있는지 확인하고, 포함되어 있다면 해당 인덱스를 결과 배열에 추가합니다.
코드 예제
const values = ['michael', 'jordan', 'jackson', 'michael', 'usain',
'jackson', 'bolt', 'jackson'];
const queries = ['michael', 'jackson', 'bolt'];
const findPositions = (first, second) => {
const indices = [];
first.forEach((element, index) => {
if(second.includes(element)){
indices.push(index);
};
});
return indices;
};
console.log(findPositions(values, queries));
실행 결과
위 코드를 실행하면 콘솔에 다음과 같은 결과가 출력됩니다.
[ 0, 2, 3, 5, 6, 7 ]
코드 동작 원리
이 코드의 핵심 로직은 다음과 같습니다.
1. 빈 결과 배열 생성: 찾은 인덱스들을 저장할 indices 배열을 먼저 선언합니다.
2. 배열 순회: forEach() 메서드로 첫 번째 배열의 모든 요소를 순회하면서, 두 번째 인자로 현재 요소의 값과 인덱스를 함께 전달받습니다.
3. 포함 여부 확인: includes() 메서드를 사용해 현재 요소가 두 번째 배열에 존재하는지 검사합니다.
4. 인덱스 저장: 조건이 참이라면 push() 메서드로 해당 인덱스를 결과 배열에 추가합니다.
추가 팁: filter()와 indexOf() 활용
비슷한 결과를 얻는 또 다른 방법으로 filter() 메서드를 사용할 수도 있습니다.
const findPositionsAlt = (first, second) =>
first.map((element, index) => second.includes(element) ? index : -1)
.filter(index => index !== -1);
두 방법 모두 시간 복잡도는 O(n × m)(n은 첫 번째 배열의 길이, m은 두 번째 배열의 길이)입니다. 만약 두 번째 배열이 매우 크다면, includes() 대신 Set 객체를 사용하면 조회 성능을 O(1)로 개선할 수 있습니다.