스택큐힙리스트

JS 배열에서 중복 값을 제거 [중복] 본문

카테고리 없음

JS 배열에서 중복 값을 제거 [중복]

스택큐힙리스트 2023. 3. 23. 00:18
반응형

이 질문은 이미 답변이 있습니다.

Get all unique values in a JavaScript array (remove duplicates)

한국어로 번역하세요.

5년 전에 종료되었습니다.

제가 가진 JavaScript 배열은 중복을 포함하거나 포함하지 않을 수 있습니다.

var names = [Mike,Matt,Nancy,Adam,Jenny,Nancy,Carl];

중복을 제거하고 고유한 값을 새 배열에 넣어야 합니다.

내가 시도해본 모든 코드를 가리킬 수는 있지만, 그들이 작동하지 않기 때문에 무의미하다고 생각한다. jQuery 솔루션도 받아들일 수 있다.

비슷한 질문:

Get all non-unique values (i.e.: duplicate/more than one occurrence) in an array

답변 1

요약:

Set 생성자와 spread syntax를 사용합니다.

uniq = [...new Set(array)];

(참고로 var uniq은 배열이 됩니다...new Set()는 세트로 만들지만 [...]는 다시 배열로 변환합니다)

스마트하지만 순진한 방법

uniqueArray = a.filter(function(item, pos) {

return a.indexOf(item) == pos;

})

기본적으로 우리는 배열을 반복하며 각 요소마다 해당 요소의 첫 번째 위치가 현재 위치와 같은지 확인합니다. 당연히 중복되는 요소의 경우 두 위치는 다릅니다.

필터 콜백의 3번째(이 배열) 매개변수를 사용하여 배열 변수의 클로저를 피할 수 있습니다:

uniqueArray = a.filter(function(item, pos, self) {

return self.indexOf(item) == pos;

})

비록 간결하지만, 이 알고리즘은 큰 배열에 대해서는 효율적이지 않습니다 (이차 시간).

해시테이블이 해결책이 됩니다.

function uniq(a) {

var seen = {};

return a.filter(function(item) {

return seen.hasOwnProperty(item) ? false : (seen[item] = true);

});

}

이렇게 일반적으로 수행됩니다. 아이디어는 각 요소를 해시 테이블에 배치 한 다음 즉시 존재 여부를 확인하는 것입니다. 이렇게하면 선형 시간이 소요되지만 적어도 두 가지 단점이 있습니다.

자바스크립트에서 해시 키는 문자열 또는 심볼만 가능하기 때문에이 코드는 숫자와 숫자 문자열을 구분하지 않습니다. 즉, uniq([1,1])는 그냥 [1]를 반환합니다.

동일한 이유로, 모든 객체는 동등하게 간주됩니다: uniq([{foo:1},{foo:2}]) 는 단지 [{foo:1}]를 반환합니다.

그렇지만, 만약 당신의 배열이 기본 자료형만 포함하고 타입이 중요하지 않다면 (예를 들면 항상 숫자인 경우), 이 해결책은 최적입니다.

두 세계에서의 최고의 것

범용 솔루션은 두 가지 접근 방식을 결합합니다. 이는 기본 해시 조회를 사용하면서 객체에 대해서는 선형 검색을 적용합니다.

function uniq(a) {

var prims = {boolean:{}, number:{}, string:{}}, objs = [];

return a.filter(function(item) {

var type = typeof item;

if(type in prims)

return prims[type].hasOwnProperty(item) ? false : (prims[type][item] = true);

else

return objs.indexOf(item) >= 0 ? false : objs.push(item);

});

}

정렬 | 중복제거

다른 옵션은 먼저 배열을 정렬하고, 이전 요소와 같은 요소를 하나씩 제거하는 것입니다.

function uniq(a) {

return a.sort().filter(function(item, pos, ary) {

return !pos || item != ary[pos - 1];

});

}

다시 말하지만, 이 방법은 객체와 함께 사용할 수 없습니다 (sort 떄문에 모든 객체가 동일합니다). 또한 부수 효과로 원래의 배열을 조용히 변경합니다 - 이것은 좋지 않습니다! 그러나 입력이 이미 정렬되어있는 경우에는 이 방법이 적합합니다 (위의 sort을 제거하면 됩니다).

독특함은...

때로는 등등호 이외의 기준에 따라 목록을 고유하게 만드는 것이 바람직합니다. 예를 들어, 다른 것이지만 일부 속성을 공유하는 객체를 필터링하는 것입니다. 이것은 콜백을 전달하여 우아하게 수행 할 수 있습니다. 이 키콜백은 각 요소에 적용되며 동일한 키를 가진 요소가 제거됩니다. key 가 원시값을 반환하도록 예상되므로 해시 테이블이 여기에서 잘 작동합니다.

function uniqBy(a, key) {

var seen = {};

return a.filter(function(item) {

var k = key(item);

return seen.hasOwnProperty(k) ? false : (seen[k] = true);

})

}

특히 유용한 key()은 (은) JSON.stringify로 물리적으로 다르지만 보여지는 동일한 객체를 제거할 수 있습니다.

a = [[1,2,3], [4,5,6], [1,2,3]]

b = uniqBy(a, JSON.stringify)

console.log(b) // [[1,2,3], [4,5,6]]

만약 key이 원시적이지 않다면, 선형 검색에 의존해야합니다.

function uniqBy(a, key) {

var index = [];

return a.filter(function (item) {

var k = key(item);

return index.indexOf(k) >= 0 ? false : index.push(k);

});

}

ES6에서는 Set을 사용할 수 있습니다.

function uniqBy(a, key) {

let seen = new Set();

return a.filter(item => {

let k = key(item);

return seen.has(k) ? false : seen.add(k);

});

}

또는 Map :

function uniqBy(a, key) {

return [

...new Map(

a.map(x => [key(x), x])

).values()

]

}

반면에 이것들은 원시 키가 아닌 경우에도 작동합니다.

처음이니까 끝이니까?

객체를 키로 제거할 때, 동일한 객체 중 첫 번째나 마지막 하나를 유지하고 싶을 수 있습니다.

첫 번째를 유지하기 위해 Set 변형을 사용하고 마지막을 유지하기 위해 Map를 사용하십시오.

function uniqByKeepFirst(a, key) {

let seen = new Set();

return a.filter(item => {

let k = key(item);

return seen.has(k) ? false : seen.add(k);

});

}

function uniqByKeepLast(a, key) {

return [

...new Map(

a.map(x => [key(x), x])

).values()

]

}

//

data = [

{a:1, u:1},

{a:2, u:2},

{a:3, u:3},

{a:4, u:1},

{a:5, u:2},

{a:6, u:3},

];

console.log(uniqByKeepFirst(data, it => it.u))

console.log(uniqByKeepLast(data, it => it.u))

도서관

양쪽의 underscore와 Lo-Dash은 uniq 방법을 제공합니다. 그들의 알고리즘은 기본적으로 위의 첫 번째 코드 조각과 유사하며 다음과 같이 단순화됩니다.

var result = [];

a.forEach(function(item) {

if(result.indexOf(item) < 0) {

result.push(item);

}

});

이것은 이차 방정식이지만 네이티브 indexOf를 래핑하거나 (iteratee로 말하는) 키로 uniqify할 수 있는 좋은 추가 기능이 있으며 이미 정렬된 배열에 대한 최적화도 있습니다.

jQuery를 사용하고 달러 기호 없는 것을 참을 수 없다면 다음과 같이 입력하면 됩니다.

$.uniqArray = function(a) {

return $.grep(a, function(item, pos) {

return $.inArray(item, a) === pos;

});

}

이것은 다시 말해 첫 번째 스니펫의 변형이다.

성능

자바스크립트에서 함수 호출은 비용이 비싸므로 위의 솔루션은 간결하지만 효율적이지 않습니다. 최대 성능을 위해 filter를 루프로 대체하고 다른 함수 호출을 제거하십시오.

function uniq_fast(a) {

var seen = {};

var out = [];

var len = a.length;

var j = 0;

for(var i = 0; i < len; i++) {

var item = a[i];

if(seen[item] !== 1) {

seen[item] = 1;

out[j++] = item;

}

}

return out;

}

이런 추한 코드 조각은 이전의 코드 조각 #3과 동일한 작업을하지만, 10 배 더 빠르게 수행됩니다. (2017 년 기준으로, JS 코어 개발자들은 훌륭한 일을 하고 있어서 두 배 더 빠르게 작동합니다!)

function uniq(a) {

var seen = {};

return a.filter(function(item) {

return seen.hasOwnProperty(item) ? false : (seen[item] = true);

});

}

function uniq_fast(a) {

var seen = {};

var out = [];

var len = a.length;

var j = 0;

for(var i = 0; i < len; i++) {

var item = a[i];

if(seen[item] !== 1) {

seen[item] = 1;

out[j++] = item;

}

}

return out;

}

/////

var r = [0,1,2,3,4,5,6,7,8,9],

a = [],

LEN = 1000,

LOOPS = 1000;

while(LEN--)

a = a.concat(r);

var d = new Date();

for(var i = 0; i < LOOPS; i++)

uniq(a);

document.write('
uniq, ms/loop: ' + (new Date() - d)/LOOPS)

var d = new Date();

for(var i = 0; i < LOOPS; i++)

uniq_fast(a);

document.write('
uniq_fast, ms/loop: ' + (new Date() - d)/LOOPS)

ES6 (ECMAScript 6)

ES6는 일괄적으로 Set 객체를 제공하여 일을 훨씬 쉽게 만듭니다.

function uniq(a) {

return Array.from(new Set(a));

}

또는

let uniq = a => [...new Set(a)];

파이썬과는 달리, ES6 세트는 삽입 순서로 반복되므로, 이 코드는 원래 배열의 순서를 유지합니다.

그러나 고유한 요소로 구성된 배열이 필요하다면, 처음부터 집합을 사용하는 것이 어떨까요?

발전기

같은 원리로 게으른 생성기 기반의 uniq 버전을 만들 수 있습니다.

인자에서 다음 값 가져오기

이미 본 것이면 건너뛰세요

그렇지 않으면, 그것을 양도하고 이미 본 값 집합에 추가합니다.

function* uniqIter(a) {

let seen = new Set();

for (let x of a) {

if (!seen.has(x)) {

seen.add(x);

yield x;

}

}

}

// example:

function* randomsBelow(limit) {

while (1)

yield Math.floor(Math.random() * limit);

}

// note that randomsBelow is endless

count = 20;

limit = 30;

for (let r of uniqIter(randomsBelow(limit))) {

console.log(r);

if (--count === 0)

break

}

// exercise for the reader: what happens if we set `limit` less than `count` and why

답변 2

주제: JS 배열에서 중복 값 제거하기 [중복 제거하기]

JavaScript는 현재 인기있는 프로그래밍 언어 중 하나이며 웹 개발에 매우 유용합니다. 하지만 때로는 배열에 중복 값이 포함되어 있을 경우 이를 제거해야 할 때가 있습니다.

이 문제를 해결하기 위해서는 JavaScript에서 제공하는 기본 함수 중 하나인 'filter'함수를 사용할 수 있습니다. 이 함수는 배열 요소를 필터링하여 새로운 배열을 반환합니다.

그러나 중복 값 제거에 대한 별도의 메서드는 존재하지 않기 때문에 몇 가지 고급 기술을 사용해야 합니다. 이를 위해 ES6에서 소개한 Set 객체를 활용하여 중복 값이 포함되지 않은 새로운 배열을 생성할 수 있습니다.

Set 객체는 고유한 값만 저장할 수 있는 컬렉션 객체이며, 중복 값이 포함되어 있지 않은 새로운 배열을 만드는 데 사용할 수 있습니다. 이를 이용하여 세부적인 코드를 작성할 수 있습니다.

예를 들어, 다음과 같은 코드를 사용하여 배열에서 중복 값을 제거할 수 있습니다.

```javascript

var arr = [1, 2, 2, 3, 4, 4, 5];

var uniqueArr = [...new Set(arr)];

console.log(uniqueArr); // [1, 2, 3, 4, 5]

```

위의 코드에서는 배열 arr에 중복 값이 포함되어 있고, Set 객체를 사용하여 중복을 제거한 새로운 배열 uniqueArr를 생성합니다. 이때, 중복 값을 제거하는 것이 목적이므로 Set 생성자를 사용하는 것보다 Spread 구문을 사용하는 것이 유리합니다.

이와 같은 방법을 사용하여 JavaScript 배열에서 중복 값을 제거할 수 있습니다. 이를 통해 배열을 효율적으로 관리할 수 있으며, 불필요한 연산을 방지하여 성능을 향상할 수 있습니다.

따라서 JavaScript를 사용하여 프로그래밍을 하는 경우, 배열에서 중복 값을 제거하는 것이 필요한 경우 'Set' 객체를 사용하여 처리하면 코드의 효율성을 높일 수 있다는 것을 기억해주세요.

반응형
Comments