JavaScript 배열의 중복 제거, 2차원 배열의 중복 제거

Jinny·2022년 3월 20일

우선 1차원 배열에서의 중복 제거 방법을 알아보자.

1. set

set은 ES6에서 등장한 새로운 data object이다. set내의 값은 유일하기 때문에 중복값이 존재하는 array를 넣게 되면 중복되는 값이 사라진다. ⇒ 가장 성능이 좋음(빠르다)

let arr = [1, 1, 2, 3, 4];
let uniqueSet = new Set(arr);
let uniqueArr = [...new Set(arr)]; // ... : 스프레드 연산자
console.log(uniqueArr);

//result : 
//Set(4) { 1, 2, 3, 4 }
//[1, 2, 3, 4]

2. filter

  • filter : 배열의 각 원소들을 콜백함수로 검사하여 true를 반환하는 요소들만 모아 배열로 리턴
  • indexOf : 배열에서 지정된 요소를 찾을 수 있는 첫 번째 인덱스를 반환, 존재하지 않으면 -1반환
let arr = [1, 1, 2, 3, 4];
let uniqueArr = arr.filter((element, index)=>{
	//element : 현재 순회중인 요소
  //index : 현재 순회중인 요소의 인덱스
	return arr.indexOf(element) === index;
});
console.log(uniqueArr);

//result : [1, 2, 3, 4]

3. forEach

let arr = [1, 1, 2, 3, 4];
let uniqueArr = [];
arr.forEach((element) => {
//배열 전체를 순회하면서 uniqueArr에 현재 순회중인 element가 존재하지 않는다면 push
	if(!uniqueArr.includes(element)){
		uniquArr.push(element);
	}
});
console.log(uniqueArr);

//result : [1, 2, 3, 4]

2차원 배열 중복 제거

위와 같이 1차원 배열에서의 중복 제거 방법을 보고 2차원 배열 중복 제거 시, 위와 같이 set 방식을 사용해봤는데 안된다!

let arr = [
  [1, 1],
  [1, 1],
  [1, 2],
  [1, 3],
];
let uniqueArr = new Set(arr);
console.log(uniqueArr);
// result = Set(4) { [ 1, 1 ], [ 1, 1 ], [ 1, 2 ], [ 1, 3 ] }

그래서 아래와 같은 방식을 사용했음
우선 indexOf와 findIndex의 차이를 알아보자

🌞 indexOf
: 지정된 요소와 일치하는 첫번째 인덱스를 반환

// 2차원 배열에서는 첫번째 인덱스를 반환안하고 해당 요소의 인덱스를 반환함
let locations = [
  [126, 34],
  [126, 34],
  [126, 35],
  [127, 34],
];
let uniqueArr = locations.filter((element, index) => {
  console.log(locations.indexOf(element));
  return locations.indexOf(element) === index;
});
console.log(uniqueArr);

//result : 
//0
//1
//2
//3
//[ [ 126, 34 ], [ 126, 34 ], [ 126, 35 ], [ 127, 34 ] ]

🌞 findIndex
: 주어진 판별함수를 만족하는 배열의 첫 번째 요소에 대한 인덱스를 반환
indexOf와 달리 함수를 통해 검사함 ⇒ 2차원 배열의 0,1번 요소 각각을 비교하는 판별함수를 사용함

//경위도 좌표가 담긴 2차원 배열
let locations = [
  [126, 34],
  [126, 34],
  [126, 35],
  [127, 34],
];
let uniqueArr = locations.filter((element, index) => {
  return (
		//1차원 배열에서는 indexOf를 사용했지만 다차원 배열에서는 안먹힘
    locations.findIndex(
      (item) => item[0] === element[0] && item[1] === element[1]
    ) === index
  );
});
console.log(uniqueArr);
//result : [ [ 126, 34 ], [ 126, 35 ], [ 127, 34 ] ]

💣그런데...!

대량의 데이터를 위의 방식으로 중복 제거를 하니까, 너무 오랜 시간이 소요되는 것...

뭐지뭐지 다른 방법을 찾다가 요기서 찾은 방법을 사용해보니까 훨씬 빠르게 동작했다😆

//최종 변경 코드
let locations = [
  [126, 34],
  [126, 34],
  [126, 35],
  [127, 34],
];

function removeDup(arr) {
  return [...new Set(arr.join("|").split("|"))]
    .map((v) => v.split(","))
    .map((v) => v.map((a) => +a));
}

let uniqueArr = removeDup(locations);
console.log(uniqueArr);

와 근데 왤케 어려워...ㅠㅠ

다차원 배열은 set 형태로 만들어봤자, 그대로니까 요걸 문자열 형태의 1차원 배열로 만든 다음에 set으로 만들어서 중복을 제거하고 다시 2차원 배열의 형태로 돌리는 방식인데,

하나씩 뜯어보자

🔎 join, split

- join : 배열의 모든 요소를 연결해 하나의 문자열로 만든다.
console.log(locations.join("|")); // 126,34|126,34|126,35|127,34

- split : String 객체를 지정한 구분자를 이용해 여러개의 문자열로 나눈다.
console.log(location.join("|").split("|")); //[ '126,34', '126,34', '126,35', '127,34' ]
자자 그럼 이제 set을 사용해서 중복 제거가 가능하겠즁~!

console.log([...new Set(location.join("|").split("|"))]); 
//[ '126,34', '126,35', '127,34' ]

🔎 map

: 배열 내의 모든 요소에 대하여 주어진 함수를 호출한 결과를 모아 새로운 배열로 반환

let unique = [...new Set(locations.join("|").split("|"))];
console.log(unique.map((v) => v.split(",")));
// [ [ '126', '34' ], [ '126', '35' ], [ '127', '34' ] ]

🔎 산술 연산자(Arithmetic Operators)

: mdn 이건 ㄹㅇ 첨보는거다... 🧐

* Unaray plus(+) 
+"3" returns 3, +true returns 1

v.map((a) => +a) 
이게 대체 뭔뜻인가 했더니 문자열을 숫자로 바꿔주는 것이였다....
단항연산자 : 피연산자가 숫자가 아니라면 숫자 형태로 바꾸는 기능을 한다.
mdn에서는 해당 연산자가 무언가를 숫자로 변경하는 가장 빠른 방법이라고도 적혀있다. 
* unary plus is the fastest and preferred way of converting something into a number

let uniqueArr = [
  ["126", "34"],
  ["126", "35"],
  ["127", "34"],
];
console.log(uniqueArr.map((v) => v.map((a) => +a)));
v는 ["126", "34"]와 같은 요소 하나하나
a는 그안에 있는 요소에 접근하는 것으로 "126"과 같은 문자열 요소들을 숫자로 바꿔준다.
// [ [ 126, 34 ], [ 126, 35 ], [ 127, 34 ] ]

틀린 부분이 있거나, 더 좋은 방법이 있다면 알려주세용~!!

참고한 사이트 출처

profile
조금씩 매일 성장해나가고 싶은 병아리 개발자입니다:)