추천 도서: JavaScript 학습 노트: 배열 추가, 삭제, 수정 및 확인
인터뷰에서 면접관들은 JavaScript에서 배열 중복 제거를 구현하는 방법에 대해 자주 질문합니다. 최근 저는 JavaScript 배열에 대해 배우게 되었고, 이번 기회에 JavaScript에서 배열 중복 제거를 위한 몇 가지 방법을 정리했습니다.
다음 어레이 중복 제거 방법은 제가 직접 수집하여 정리한 것입니다. 오류가 있는 경우 본문에서 오류를 지적해 주시기 바랍니다.
이중 루프 중복 제거
이 방법은 순회를 위해 두 개의 for 루프를 사용합니다. 전체 아이디어는 다음과 같습니다.
중복 제거된 배열을 저장할 빈 배열 구성
외부 for 루프는 원래 배열을 순회하며 매번 배열에서 요소를 꺼내 결과 배열과 비교합니다
원래 배열에서 가져온 요소가 결과 배열의 요소와 동일하면 루프를 중단하고, 그렇지 않으면 결과 배열에 저장합니다.
코드는 다음과 같습니다.
Array.prototype.unique1 = function () { // 构建一个新数组,存放结果 var newArray = [this[0]]; // for循环,每次从原数组中取出一个元素 // 用取出的元素循环与结果数组对比 for (var i = 1; i < this.length; i++) { var repeat = false; for (var j=0; j < newArray.length; j++) { // 原数组取出的元素与结果数组元素相同 if(this[i] == newArray[j]) { repeat = true; break; } } if(!repeat) { // 如果结果数组中没有该元素,则存放到结果数组中 newArray.push(this[i]); } } return newArray; }
다음과 같은 배열이 있다고 가정해 보겠습니다.
var arr = [1,2,3,4,'a','b',1,3,4,56,32,34,2,'b','c',5,'1',`2`]; arr.unique1(); // [1, 2, 3, 4, "a", "b", 56, 32, 34, "c", 5]
이 방법은 시간이 많이 걸리고 성능 집약적이라고 합니다. 간단한 테스트를 해보세요(테스트 방법이 잘못 작성되었습니다):
function test () { var arr = []; for (var i = 0; i < 1000000; i++) { arr.push(Math.round(Math.random(i) * 10000)); } doTest(arr, 1); } function doTest(arr, n) { var tStart = (new Date()).getTime(); var re = arr.unique1(); var tEnd = (new Date()).getTime(); console.log('双重循环去重方法使用时间是:' + (tEnd - tStart) + 'ms'); return re; } test();
Chrome 컨트롤러에서 위 코드를 실행하고 이중 루프 중복 제거에 걸리는 시간을 테스트합니다: 11031ms.
위 메서드는 forEach() 메서드와 indexOf() 메서드를 사용하여 시뮬레이션할 수 있습니다.
function unique1() { var newArray = []; this.forEach(function (index) { if (newArray.indexOf(index) == -1) { newArray.push(index); } }); return newArray; }
unique1.apply(arr) 또는 Unique1.call(arr)을 통해 호출하세요. 그러나 이 방법은 훨씬 더 효율적입니다. 위의 동일한 테스트 코드는 5423ms를 소요하며 이는 거의 절반의 속도입니다.
순회 정렬하여 중복 제거
먼저 sort() 메서드를 사용하여 원본 배열을 정렬한 후 배열을 순회하여 배열의 i번째 요소가 결과 배열의 마지막 요소와 동일한지 확인합니다. 다른 경우 요소는 결과 배열에 배치됩니다.
Array.prototype.unique2 = function () { // 原数组先排序 this.sort(); // 构建一个新数组存放结果 var newArray = []; for (var i = 1; i < this.length; i++) { // 检查原数中的第i个元素与结果中的最后一个元素是否相同 // 因为排序了,所以重复元素会在相邻位置 if(this[i] !== newArray[newArray.length - 1]) { // 如果不同,将元素放到结果数组中 newArray.push(this[i]); } } return newArray; }
예:
var arr = [1,2,3,4,'a','b',1,3,4,56,32,34,2,'b','c',5,'1','2']; arr.unique2(); // ["1", 1, 2, "2", 3, 32, 34, 4, 5, 56, "a", "b", "c"]
이 방법에는 두 가지 특징이 있습니다.
중복 제거 후 배열이 정렬됩니다. 이는 주로 중복 제거 전에 원래 숫자가 정렬되었기 때문입니다
중복 제거 후 배열에서 '1', 1 등 숫자와 동일한 숫자는 구분할 수 없습니다
동일한 방법을 사용하면 테스트 시간은 1232ms입니다.
객체 키-값 쌍 방식
이 중복 제거 방법의 구현 아이디어는 다음과 같습니다.
JavaScript 개체 및 새 배열 만들기
for 루프를 사용하여 원래 배열을 순회하면서 매번 하나의 요소를 꺼내어 JavaScript 객체의 키와 비교합니다
포함되지 않은 경우 객체에 저장된 요소의 값을 결과 배열에 푸시하고, 객체 객체에 저장된 속성 이름의 값을 1로 설정합니다
코드는 다음과 같습니다.
Array.prototype.unique3 = function () { // 构建一个新数组存放结果 var newArray = []; // 创建一个空对象 var object = {}; // for循环时,每次取出一个元素与对象进行对比 // 如果这个元素不重复,则将它存放到结果数中 // 同时把这个元素的内容作为对象的一个属性,并赋值为1, // 存入到第2步建立的对象中 for (var i = 0; i < this.length; i++){ // 检测在object对象中是否包含遍历到的元素的值 if(!object[typeof(this[i]) + this[i]]) { // 如果不包含,将存入对象的元素的值推入到结果数组中 newArray.push(this[i]); // 如果不包含,存入object对象中该属性名的值设置为1 object[typeof(this[i]) + this[i]] = 1; } } return newArray; }
이전 예제 실행:
var arr = [1,2,3,4,'a','b',1,3,4,56,32,34,2,'b','c',5,'1','2']; arr.unique3(); // [1, 2, 3, 4, "a", "b", 56, 32, 34, "c", 5, "1", "2"]
마찬가지로, 서로 다른 키가 같은 것으로 오해될 수 있습니다. 예: a[1], a["1"] . 이 방법에 소요된 시간: 621ms. 이 방법은 시간은 가장 짧지만 메모리를 더 많이 차지합니다.
위의 방법 외에도 다음과 같은 여러 가지 방법이 있습니다.
// 方法四 Array.prototype.unique4 = function () { // 构建一个新数组存放结果 var newArray = []; // 遍历整个数组 for (var i = 0; i < this.length; i++) { // 遍历是否有重复的值 for (j = i + 1; j < this.length; j++) { // 如果有相同元素,自增i变量,跳出i的循环 if(this[i] === this[j]) { j = ++i; } } // 如果没有相同元素,将元素推入到结果数组中 newArray.push(this[i]); } return newArray; }
크롬 테스트 결과
var arr = [1,2,3,4,'a','b',1,3,4,56,32,34,2,'b','c',5,'1','2']; arr.unique4(); // ["a", 1, 3, 4, 56, 32, 34, 2, "b", "c", 5, "1", "2"]
마찬가지로 1과 '1'은 구별할 수 없습니다.
// 方法五 Array.prototype.unique5 = function () { // 构建一个新数组存放结果 var newArray = []; // 遍历整个数组 for (var i = 0; i < this.length; i++) { // 如果当前数组的第i值保存到临时数组,那么跳过 var index = this[i]; // 如果数组项不在结果数组中,将这个值推入结果数组中 if (newArray.indexOf(index) === -1) { newArray.push(index); } } return newArray; }
Chrome 테스트 결과:
var arr = [1,2,3,4,'a','b',1,3,4,56,32,34,2,'b','c',5,'1','2']; arr.unique6(); // [1, 2, 3, 4, "a", "b", 56, 32, 34, "c", 5, "1", "2"]
마찬가지로 1과 '1'은 구별할 수 없습니다. 소요 시간: 14361ms.
// 方法六 Array.prototype.unique6 = function () { return this.reduce(function (newArray, index) { if(newArray.indexOf(index) < 0) { newArray.push(index); } return newArray; },[]); }
테스트 결과는 다음과 같습니다.
var arr = [1,2,3,4,'a','b',1,3,4,56,32,34,2,'b','c',5,'1','2']; arr.unique6(); // [1, 2, 3, 4, "a", "b", 56, 32, 34, "c", 5, "1", "2"]
소요 시간: 16490ms.
// 方法七 Array.prototype.unique7 = function(){ var newArray; newArray = this.filter(function (ele,i,arr) { return arr.indexOf(ele) === i; }); return newArray; }
테스트 결과:
var arr = [1,2,3,4,'a','b',1,3,4,56,32,34,2,'b','c',5,'1','2']; arr.unique6(); // [1, 2, 3, 4, "a", "b", 56, 32, 34, "c", 5, "1", "2"]
걸린 시간: 13201ms.
여러 가지 방법이 있지만 이에 비해 다음 방법이 더 나은 해결책입니다.
Array.prototype.unique3 = function () { // 构建一个新数组存放结果 var newArray = []; // 创建一个空对象 var object = {}; // for循环时,每次取出一个元素与对象进行对比 // 如果这个元素不重复,则将它存放到结果数中 // 同时把这个元素的内容作为对象的一个属性,并赋值为1, // 存入到第2步建立的对象中 for (var i = 0; i < this.length; i++){ // 检测在object对象中是否包含遍历到的元素的值 if(!object[typeof(this[i]) + this[i]]) { // 如果不包含,将存入对象的元素的值推入到结果数组中 newArray.push(this[i]); // 如果不包含,存入object对象中该属性名的值设置为1 object[typeof(this[i]) + this[i]] = 1; } } return newArray; }
그러나 ES6에는 다음과 같이 더 간단하고 최적화된 중복 제거 솔루션이 있습니다.
// ES6 function unique (arr) { const seen = new Map() return arr.filter((a) => !seen.has(a) && seen.set(a, 1)) } // or function unique (arr) { return Array.from(new Set(arr)) }
위는 배열에서 중복을 제거하기 위해 편집자가 소개한 JavaScript 학습 노트입니다. 도움이 되길 바랍니다!