자바 스크립트 배열에서 모든 고유 한 값 가져 오기 (중복 제거)


1484

고유 해야하는 숫자 배열이 있습니다. 인터넷에서 아래 코드 스 니펫을 발견했으며 배열에 0이 될 때까지 훌륭하게 작동합니다. Stack Overflow에서 거의 다른 것처럼 보이는 다른 스크립트를 찾았 지만 실패하지는 않습니다.

그래서 내가 배우는 것을 돕기 위해 누군가가 프로토 타입 스크립트가 잘못되는 것을 결정하도록 도울 수 있습니까?

Array.prototype.getUnique = function() {
 var o = {}, a = [], i, e;
 for (i = 0; e = this[i]; i++) {o[e] = 1};
 for (e in o) {a.push (e)};
 return a;
}

중복 질문에서 더 많은 답변 :

비슷한 질문 :


3
@hippietrail 그 오래된 질문은 복제본 만 찾아서 반환하는 것에 관한 것입니다 (나도 혼란 스러웠습니다!). 내 질문은 배열에 0이있을 때이 함수가 실패하는 이유에 대한 것입니다.
Mottie

질문 제목을 덜 모호하게 만들고 싶을 수도 있습니다.
hippietrail

미래의 독자들을 위해 데이터 구조의 내용을 항상 알고리즘 적으로 수정하거나 (순서, 반복 요소 제거 등) 반복 할 때마다 내부의 요소를 검색해야한다는 것을 알게되면 안전하다고 가정하는 것이 안전합니다. 먼저 잘못된 데이터 구조를 사용하고 있으며 현재 작업에 더 적합한 구조를 사용하십시오 (이 경우 배열 대신 해시 세트).
nurettin

전 다른 곳에서 코드를 복사했습니다.하지만 전에는 꽤 간단합니다. o= object, a= array, i= indexe= 음, 뭔가 : P
Mottie

답변:


2658

자바 스크립트 1.6 / 인 ECMAScript 5 당신은 기본 사용할 수있는 filter고유 한 값으로 배열을 얻기 위해 다음과 같은 방법으로 배열의 방법 :

function onlyUnique(value, index, self) { 
    return self.indexOf(value) === index;
}

// usage example:
var a = ['a', 1, 'a', 2, '1'];
var unique = a.filter( onlyUnique ); // returns ['a', 1, 2, '1']

네이티브 메소드 filter는 배열을 반복하여 주어진 콜백 함수를 전달하는 항목 만 남겨 둡니다 onlyUnique.

onlyUnique주어진 값이 처음 발생하는지 확인합니다. 그렇지 않은 경우 복제본이어야하며 복사되지 않습니다.

이 솔루션은 jQuery 또는 prototype.js와 같은 추가 라이브러리없이 작동합니다.

혼합 값 유형을 가진 배열에서도 작동합니다.

오래된 브라우저 (<IE9), 즉, 네이티브 메소드를 지원하지 않습니다 filter그리고 indexOf당신을위한 MDN 문서의 작업 방법을 찾을 수 있습니다 필터같이 IndexOf .

마지막으로 나타나는 값을 유지하려면 다음과 같이 간단히 바꾸십시오 indexOf.lastIndexOf .

ES6을 사용하면 다음과 같이 단축 될 수 있습니다.

// usage example:
var myArray = ['a', 1, 'a', 2, '1'];
var unique = myArray.filter((v, i, a) => a.indexOf(v) === i); 

// unique is ['a', 1, 2, '1']

Camilo Martin 에게 감사합니다의견에 힌트를 에게 .

ES6에는 Set고유 한 값을 저장 하는 기본 개체 가 있습니다. 고유 한 값을 가진 배열을 얻으려면 다음과 같이하십시오 :

var myArray = ['a', 1, 'a', 2, '1'];

let unique = [...new Set(myArray)]; 

// unique is ['a', 1, 2, '1']

의 생성자는 SetArray와 같은 반복 가능한 객체 를 가져오고 스프레드 연산자 ...는 집합을 다시 Array로 변환합니다. 의견에 힌트를 준 Lukas Liese 에게 감사드립니다 .


53
이 솔루션은 불행하게도 훨씬 느리게 실행됩니다. 당신은 필터와 인덱스의 한 번
Jack Franzen

18
@JackFranzen 뭐보다 느려? 라파엘 의 해결책 ? Rafaels 솔루션은 혼합 유형 배열에서 작동하지 않습니다. 내 예 ['a', 1, 'a', 2, '1']를 들어 당신은 얻을 것이다 ['a', 1, 2]. 그러나 이것은 내가 기대 한 것이 아닙니다. BTW는 속도가 훨씬 느립니다.
TLindig

25
현대 JS에서 : .filter((v,i,a)=>a.indexOf(v)==i)(뚱뚱한 화살표 표기법).
Camilo Martin

163
let unique_values = [...new Set(random_array)]; developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
Lukas Liesis

5
우선 정렬 및 다양한 데이터 유형 처리와 같은 많은 가능성을 포함하여 훨씬 자세한 답변을 보려면 stackoverflow.com/a/9229821/368896
Dan Nissenbaum

874

ES6 / ES2015에 대한 업데이트 된 답변 : Set 사용 하면 단일 라인 솔루션은 다음과 같습니다.

var items = [4,5,4,6,3,4,5,2,23,1,4,4,4]
var uniqueItems = Array.from(new Set(items))

어떤 반환

[4, 5, 6, 3, 2, 23, 1]

마찬가지로 le_m이 제안이 또한 사용을 단축 할 수 확산 연산자 처럼

var uniqueItems = [...new Set(items)]

10
공지 사항, 그 내부 배열 것없는 일Array.from(new Set([[1,2],[1,2],[1,2,3]]))
알렉산더 곤차 로프

2
이 솔루션의 성능은 myArray.filter((v, i, a) => a.indexOf(v) === i);?
Simoyw

42
Set프리미티브 값 대신 및 추가 객체 를 사용하면 객체에 대한 고유 한 참조 가 포함 됩니다. 따라서, 집합 s내의은 let s = new Set([{Foo:"Bar"}, {Foo:"Bar"}]);이 리턴 Set { { Foo: 'Bar' }, { Foo: 'Bar' } }되는 Set동일한 값을 포함하는 개체에 대한 고유의 오브젝트 참조로한다. 당신이 작성하는 경우 let o = {Foo:"Bar"};와 두 사람과 함께 다음 집합을 만들 참조가 너무 좋아 : let s2 = new Set([o,o]);다음 S2 될 것입니다Set { { Foo: 'Bar' } }
mortb

2
이 두 옵션 모두 polyfill.io 레이어가있는 경우에도 IE10에 문제가 있습니다.
Thymine

2
새로운 테스트 케이스 jsperf.com/array-filter-unique-vs-new-set/1 것 같다 new Set의 트로피
shuk

167

나는이 질문에 이미 30 개 이상의 답변이 있음을 알고 있습니다. 그러나 나는 기존의 모든 대답을 먼저 읽고 내 자신의 연구를했습니다.

나는 모든 대답을 4 가지 가능한 해결책으로 나눕니다.

  1. 새로운 ES6 기능을 사용하십시오. [...new Set( [1, 1, 2] )];
  2. { }중복을 방지하기 위해 객체 를 사용
  3. 헬퍼 배열 사용 [ ]
  4. 사용하다 filter + indexOf

답변에서 찾은 샘플 코드는 다음과 같습니다.

새로운 ES6 기능을 사용하십시오. [...new Set( [1, 1, 2] )];

function uniqueArray0(array) {
  var result = Array.from(new Set(array));
  return result    
}

{ }중복을 방지하기 위해 객체 를 사용

function uniqueArray1( ar ) {
  var j = {};

  ar.forEach( function(v) {
    j[v+ '::' + typeof v] = v;
  });

  return Object.keys(j).map(function(v){
    return j[v];
  });
} 

헬퍼 배열 사용 [ ]

function uniqueArray2(arr) {
    var a = [];
    for (var i=0, l=arr.length; i<l; i++)
        if (a.indexOf(arr[i]) === -1 && arr[i] !== '')
            a.push(arr[i]);
    return a;
}

사용하다 filter + indexOf

function uniqueArray3(a) {
  function onlyUnique(value, index, self) { 
      return self.indexOf(value) === index;
  }

  // usage
  var unique = a.filter( onlyUnique ); // returns ['a', 1, 2, '1']

  return unique;
}

그리고 어느 것이 더 빠른지 궁금했습니다. 샘플 Google 스프레드 시트를 만들었습니다.기능을 테스트하기 위해 를 . 참고 : ECMA 6은 Google 스프레드 시트에서 사용할 수 없으므로 테스트 할 수 없습니다.

테스트 결과는 다음과 같습니다. 여기에 이미지 설명을 입력하십시오

{ }해시를 사용하기 때문에 객체 를 사용하는 코드 가 승리 할 것으로 예상 했습니다. 테스트 결과 Chrome 및 IE에서이 알고리즘에 대한 최상의 결과를 보여주었습니다. 코드를 위한 @rab에 감사합니다 .


"filter + indexOf"옵션은 100.000 개가 넘는 항목에서 매우 느립니다. "객체 맵"접근 방식을 사용해야했지만 원래 정렬이 깨졌습니다.
liberborn

숫자가 높을수록 느리지 않습니까?
fletchsod 2015 년

3
@ fletchsod, 숫자는 코드를 실행하는 시간 (ms)입니다.
Max Makhrov 2016 년

1
숫자는 wong입니다! Google 앱 스크립트는 클라이언트 브라우저가 아닌 서버에서 실행되므로 Chrome / IE (또는 거의 모든 브라우저)의 성능이 동일합니다!
Jay Dadhania

1
하지만 이 가능하다 (중 하나를 통해 구글 스크립트에서 클라이언트 측 JS를 실행 google.script.host 또는 google.script.run -하지 않도록한다), 대답은 명확하게한다고 "ECMA 6 구글 스프레드 시트에서 사용 가능한 아니다" - 그러므로 우리는 포스터가 이것을 위해 서버 측 Google Script를 사용했다고 가정 할 수 있습니다. 따라서 대답은 브라우저가 아닌 Google 서버의 성능을 보여줍니다!
Jay Dadhania

134

underscore.js를 사용할 수도 있습니다 .

console.log(_.uniq([1, 2, 1, 3, 1, 4]));
<script src="http://underscorejs.org/underscore-min.js"></script>

다음을 반환합니다 :

[1, 2, 3, 4]

22
이 사람들을 수행하십시오. Array 프로토 타입에 무언가를 넣지 마십시오. 부디.
Jacob Dalton

5
@JacobDalton-이것은 배열 프로토 타입을 확장하지 않습니다. _ 객체에 네임 스페이스가 있습니다.
superluminary 2016 년

24
@ superluminary 나는 이것이 제발 그렇게 말한 이유를 알고 있습니다. 수용된 솔루션은 어레이 프로토 타입 수정을 제안합니다. 그렇게하지 마십시오.
Jacob Dalton

20
@JacobDalton이 작업을 수행하지 마십시오. 작은 작업으로 추가 라이브러리를 추가 할 필요가 없습니다.array = [...new Set(array)]

3
이로 인해 ES 기능을 사용하고 더 많은 라이브러리를 추가하는 것이 웹 사이트를 부풀려 버리는 목적을 무너 뜨 렸습니다.
fletchsod 2015 년

68

하나의 라이너, 순수한 JavaScript

ES6 구문 사용

list = list.filter((x, i, a) => a.indexOf(x) == i)

x --> item in array
i --> index of item
a --> array reference, (in this case "list")

여기에 이미지 설명을 입력하십시오

ES5 구문 사용

list = list.filter(function (x, i, a) { 
    return a.indexOf(x) == i; 
});

브라우저 호환성 : IE9 +


13
@Spets 이차 비용이 있으므로 최상의 답변은 아닙니다
Oriol

@Spets는 모든 고유 / 고유와 같은 ... 네, 똑똑하고 기수를 사용하여 정렬하고 대부분의 경우 0 (n2) 빠른 검색보다 느립니다.
doker

고마워요! 코드를 처음 보았을 때 그것을 알지 못했지만 이제는 좀 더 분명합니다.
Spets

51

jQuery를 사용하는 멋진 메소드를 찾았습니다.

arr = $.grep(arr, function(v, k){
    return $.inArray(v ,arr) === k;
});

참고 :이 코드는 Paul Irish의 오리 펀치 포스트 에서 가져 왔습니다 .


8
간결한 솔루션이지만 inArray를 호출하는 것은 hasOwnProperty를 호출하는 것보다 덜 효율적입니다.
Mister Smith

이것도 O (N ^ 2)입니까? 사전 또는 hasOwnProperty 접근 방식은 O (N * logN) 일 수 있습니다.
speedplane

이것은 나를 위해 일했지만 Internet Explorer는 다른 모든 솔루션을 지원하지 않았습니다.
kerl

51

ES6를 사용한 최단 솔루션 : [...new Set( [1, 1, 2] )];

또는 원래 질문에서와 같이 Array 프로토 타입을 수정하려는 경우 :

Array.prototype.getUnique = function() {
    return [...new Set( [this] )];
};

EcmaScript 6은 현재 최신 브라우저 (2015 년 8 월) 에서만 일부만 구현 되지만 Babel 은 ES6 (및 ES7)을 ES5로 다시 컴파일하는 데 매우 유명해졌습니다. 그렇게하면 오늘 ES6 코드를 작성할 수 있습니다!

...의미 가 궁금하다면 스프레드 연산자 라고합니다 . From MDN :«확산 연산자를 사용하면 여러 인수 (함수 호출) 또는 여러 요소 (배열 리터럴)가 필요한 위치에서 식을 확장 할 수 있습니다». Set은 반복 가능하고 고유 한 값만 가질 수 있으므로 스프레드 연산자는 Set을 확장하여 배열을 채 웁니다.

ES6 학습을위한 자료 :


3
을 사용하면 더 짧게 할 수 a = [...Set(a)]있지만 어쨌든 이것은 Firefox에만 해당됩니다.
c69

@ c69는 그보다 짧지 않습니다. SpiderMonkey 사용자도 감사합니다.
Torsten Becker

바벨과 함께 작동합니다. 또한 shim의 Array.from도 포함하면됩니다.require ( "core-js/fn/array/from" );
Vladislav Rastrusny 2016 년

Array.prototype.getUnique = function () {return [... new Set ([this])]; }; 또는 Array.prototype.getUnique = function () {return [... new Set (this)]; }; 다음 $ ( 'body'). html (). toLowerCase (). match (/ ([a-zA-Z0-9 ._ +-] + @ [a-zA-Z0-9)에 적용했습니다. _-] + \. [a-zA-Z0-9 ._-] +) / gi) .getUnique (); 첫 번째는 두 번째 값이 중복 제거를 모두 재조정 한 경우에만 하나의 고유 한 값을 반환했습니다.
ashique

[...Set(['a', 1, 'a', 2, '1'])]그것이 유지하는 것이 현명 여전히 그래서, TypeError가 발생합니다 new:[...new Set(['a', 1, 'a', 2, '1'])]
아담 카츠

36

가장 간단한 해결책 :

var arr = [1, 3, 4, 1, 2, 1, 3, 3, 4, 1];
console.log([...new Set(arr)]);

또는:

var arr = [1, 3, 4, 1, 2, 1, 3, 3, 4, 1];
console.log(Array.from(new Set(arr)));


4
IE10 이하에서는 지원되지 않습니다. IE11 +와 Safari는 제한적인 지원을 제공합니다 (위의 예제는 확실하지는 않습니다) developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
oriadam

32

이 작업을 수행하는 가장 간단하고 빠른 방법 (Chrome) :

Array.prototype.unique = function() {
    var a = [];
    for (var i=0, l=this.length; i<l; i++)
        if (a.indexOf(this[i]) === -1)
            a.push(this[i]);
    return a;
}

단순히 배열의 모든 항목을 살펴보고 해당 항목이 이미 목록에 있는지 테스트하고 그렇지 않은 경우 반환되는 배열로 푸시합니다.

jsPerf에 따르면이 기능은 어디에서나 찾을 수있는 기능 중 가장 빠릅니다 .

비 프로토 타입 버전 :

function uniques(arr) {
    var a = [];
    for (var i=0, l=arr.length; i<l; i++)
        if (a.indexOf(arr[i]) === -1 && arr[i] !== '')
            a.push(arr[i]);
    return a;
}

정렬

배열을 정렬해야 할 때 다음이 가장 빠릅니다.

Array.prototype.sortUnique = function() {
    this.sort();
    var last_i;
    for (var i=0;i<this.length;i++)
        if ((last_i = this.lastIndexOf(this[i])) !== i)
            this.splice(i+1, last_i-i);
    return this;
}

또는 비 프로토 타입 :

function sortUnique(arr) {
    arr.sort();
    var last_i;
    for (var i=0;i<arr.length;i++)
        if ((last_i = arr.lastIndexOf(arr[i])) !== i)
            arr.splice(i+1, last_i-i);
    return arr;
}

이것은 또한 빠른 위의 방법보다 대부분의 비 크롬 브라우저한다.


Linux에서 Chrome 55.0.2883은 arr.unique ()를 선호하고 swilliams의 arrclone2.sortFilter ()는 가장 느립니다 (78 % 느림). 그러나 Firefox 51.0.0 (많은 애드온 포함)은 swilliams가 가장 빠릅니다 (아직 다른 Chrome 결과보다 여전히 Ops / sec에 의해 느려짐). mottie의 jQuery $ .grep (arr, jqFilter) 가 가장 느립니다 (46 % 느림). arr.uniq ()가 30 % 느려졌습니다. 각 테스트를 두 번 실행하여 일관된 결과를 얻었습니다. Rafael의 arr.getUnique () 는 두 브라우저 모두에서 2 위를 차지했습니다.
Adam Katz

jsPerf는 현재 버그 가 있으므로이 테스트에 대한 편집 내용이 모든 것을 커밋하지는 않았지만 두 가지 테스트가 추가되었습니다 .CoccotoUnique () 는 두 브라우저에서 Vamsi의 ES6 list.filter () 를 능가하여 swilliams의 sortFilter () FF에서 # 1의 경우 (sortFilter가 16 % 느림) Chrome에서 # 3에 대해 정렬 된 테스트 (2 % 느려짐)를 이겼습니다.
Adam Katz

아, 나는 그 테스트가 사소하게 작고 실제로 중요하지 않다는 것을 알지 못했습니다. 허용 대답에 대한 코멘트는 그 문제에 대해 설명 하고 제공에 보정 개정 라파엘의 코드를 쉽게 빠르게하고 Joetje50의 arr.unique 코드가 98 % 느리게하는 시험을. 이 의견에 언급 된대로 또 다른 수정을했습니다 .
Adam Katz

1
실제로 unique함수 에서 구현 한 알고리즘의 복잡도는 O (n ^ 2)이고 in의 알고리즘 getUnique은 O (n)입니다. 첫 번째는 작은 데이터 세트에서 더 빠를 지 모르지만 수학과 어떻게 논쟁 할 수 있습니까? :) 1e5 고유 항목의 배열에서 실행하면 후자가 더 빠를 수 있습니다.
Mikhail Dudin

31

성능 만! 이 코드는 아마도 여기의 모든 코드보다 10 배 빠를 것입니다. * 모든 브라우저에서 작동하며 메모리에 미치는 영향이 가장 적습니다.

이전 배열을 재사용 할 필요가 없다면 btw 필요한 다른 작업을 고유하게 변환하기 전에 수행하는 것이 가장 빠른 방법 일 것입니다.

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

그럼 당신은 이것을 시도 할 수 있습니다

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

function toUnique(a, b, c) { //array,placeholder,placeholder
  b = a.length;
  while (c = --b)
    while (c--) a[b] !== a[c] || a.splice(c, 1);
  return a // not needed ;)
}
console.log(toUnique(array));
//[3, 4, 5, 6, 7, 8, 9, 0, 2, 1]

이 기사를 읽는이 기능을 생각해 냈습니다 ...

http://www.shamasis.net/2009/09/fast-algorithm-to-find-unique-items-in-javascript-array/

나는 for 루프를 좋아하지 않는다. while- 루프와 같은 많은 매개 변수가 있습니다. while은 우리가 좋아하는 크롬을 제외한 모든 브라우저에서 가장 빠른 루프입니다.

어쨌든 나는 while을 사용하는 첫 번째 함수를 작성했습니다. 그렇지만 기사에서 찾은 함수보다 약간 빠릅니다.unique2()

다음 단계는 현대 js를 사용합니다. Object.keys 다른 for 루프를 js1.7의 Object.keys로 대체했습니다 (크롬 2 배 빠름); 부족한!. unique3().

이 시점에서 저는 제 고유 한 기능에 정말로 필요한 것이 무엇인지 생각하고있었습니다. 오래된 배열이 필요하지 않습니다. 빠른 기능을 원합니다. 그래서 2 개의 while 루프 + 스플 라이스를 사용했습니다.unique4()

내가 감동했다고 말할 수 없다.

크롬 : 일반적인 초당 150,000 작업이 초당 1,800,000 작업으로 증가했습니다.

즉 : 80,000 op / s vs 3,500,000 op / s

iOS : 18,000 op / s vs 170,000 op / s

사파리 : 80,000 op / s vs 6,000,000 op / s

증명 http://jsperf.com/wgu 또는 더 나은 console.time ... microtime ...을 사용하십시오.

unique5() 이전 배열을 유지하려는 경우 어떻게되는지 보여줄뿐입니다.

당신 Array.prototype이 무엇을하고 있는지 모른다면 사용하지 마십시오 . 나는 방금 복사와 과거를 많이했다. Object.defineProperty(Array.prototype,...,writable:false,enumerable:false})기본 프로토 타입을 생성하려는 경우 사용 합니다. 예 : https://stackoverflow.com/a/20463021/2450730

데모 http://jsfiddle.net/46S7g/

참고 :이 작업을 수행하면 기존 어레이가 파괴 / 독립됩니다.

위의 코드를 읽을 수없는 경우 자바 스크립트 책을 읽거나 짧은 코드에 대한 설명을 참조하십시오. https://stackoverflow.com/a/21353032/2450730

일부는 사용하고 있습니다 indexOf ...하지 마십시오 ... http://jsperf.com/dgfgghfghfghghgfhgfhfghfhgfh

빈 배열

!array.length||toUnique(array); 

4
100k 배열의 Urls (문자열)로 node.js에서 테스트되었습니다. 결과는 별도의 jsperf 당신 (동의하지만 느린 underscore.js _.uniq에 비해 2 배 ...이었다 jsperf.com/uniq-performance/5 ), 내가 :( 실망
xShirase

3
당신은 jsperf에서 올바르게 테스트하지 않습니다 ... 귀하의 예제에서는 매번 함수를 정의하지만 ... underscore.js 함수는 이미 정의되어 있습니다. 이것은 내 함수에 불이익을줍니다. 또한 3 & 4를 테스트하십시오. 또 다른 말은 혼합 변수 (문자열 및 숫자)를 사용하는 경우 a [b]! == a [c]를 a [b]! = a [c]
cocco로 바꿔야한다는 것입니다

2
jsPerf가 올바른지 확실하지 않지만 Reduce 대안 (나에게 이해하기 쉬움)이 솔루션보다 약간 94 % 빠릅니다. jsperf.com/reduce-for-diinct 편집 : 크롬에서는 속도가 느리고 Edge에서는 동일하며 Firefox에서는 빠릅니다.
Victor Ivens

3
작은 배열 / 낮은 복제 백분율로만 사용할 수 있습니다. 고유하지 않은 객체가 발견 될 때마다 엔진은 다음 과 같은 방법으로 모든 나머지 요소를 왼쪽 으로 이동 시킵니다 . 1) 반복합니다. 2) 읽습니다. 3) 새로운 위치에 작성합니다. 그리고, 그것은 또한 새로운 하나 접합 요소를 배열하고 그 결과로 ... 알고리즘 빠르게 더 큰 배열 / 더 자주 중복으로 저하 수익을 만듭니다. 1000-> 10000-> 50000 및 ~ 40 % 복제 크기의 배열의 경우 평균 소요 시간은 2-> 775-> 19113ms와 같습니다. Chrome에서 (크기는 1-> x10-> x5, 시간은 1-> x10-> x25로 변경됨)
ankhzet

1
감사. 좋은 접근법. 그러나 올바른 품목 주문은 어떻습니까?
liberborn

28

여기에 많은 답변이 초보자에게는 유용하지 않을 수 있습니다. 배열 중복 제거가 어려운 경우 프로토 타입 체인 또는 jQuery에 대해 실제로 알고 있습니까?

최신 브라우저에서 깨끗하고 간단한 솔루션은 고유 값 목록으로 설계된 Set에 데이터를 저장 하는 것입니다.

const cars = ['Volvo', 'Jeep', 'Volvo', 'Lincoln', 'Lincoln', 'Ford'];
const uniqueCars = Array.from(new Set(cars));

Array.from배열을 가지고 당신이 멋진 모든 방법 (기능)에 쉽게 액세스 할 수 있도록 배열에 설정 등을 변환하는 데 유용합니다. 같은 일을하는 다른 방법 들도 있습니다 . 그러나 Array.from세트에는 forEach 와 같은 유용한 기능이 많이 있으므로 전혀 필요하지 않을 수도 있습니다. .

이전 Internet Explorer를 지원해야하므로 Set을 사용할 수없는 경우 간단한 방법은 항목이 이미 새 배열에 있는지 확인하면서 새 배열로 항목을 복사하는 것입니다.

// Create a list of cars, with duplicates.
var cars = ['Volvo', 'Jeep', 'Volvo', 'Lincoln', 'Lincoln', 'Ford'];
// Create a list of unique cars, to put a car in if we haven't already.
var uniqueCars = [];

// Go through each car, one at a time.
cars.forEach(function (car) {
    // The code within the following block runs only if the
    // current car does NOT exist in the uniqueCars list
    // - a.k.a. prevent duplicates
    if (uniqueCars.indexOf(car) === -1) {
        // Since we now know we haven't seen this car before,
        // copy it to the end of the uniqueCars list.
        uniqueCars.push(car);
    }
});

이 기능을 즉시 재사용 할 수 있도록 기능에 추가해 봅시다.

function deduplicate(data) {
    if (data.length > 0) {
        var result = [];

        data.forEach(function (elem) {
            if (result.indexOf(elem) === -1) {
                result.push(elem);
            }
        });

        return result;
    }
}

따라서 중복을 제거하려면 이제이 작업을 수행합니다.

var uniqueCars = deduplicate(cars);

deduplicate(cars)부분 결과 라고하는 것이 됩니다함수가 완료되면 됩니다.

원하는 배열의 이름을 전달하십시오.


그건 그렇고, 나는 문자열로 가득 찬 배열을 사용하여 내 기술이 유연하다는 것을 보여주었습니다. 숫자에 제대로 작동합니다.
세스 할러데이

20
["Defects", "Total", "Days", "City", "Defects"].reduce(function(prev, cur) {
  return (prev.indexOf(cur) < 0) ? prev.concat([cur]) : prev;
 }, []);

[0,1,2,0,3,2,1,5].reduce(function(prev, cur) {
  return (prev.indexOf(cur) < 0) ? prev.concat([cur]) : prev;
 }, []);

왜 단순히 push배열을 사용하는 대신 요소를 배열에 넣지 않았는지 설명 할 수 있습니까 concat? 푸시를 사용해 보았지만 실패했습니다. 설명을 찾고 있습니다.
makenova

1
그 이유는 반환 값에 있습니다. concat은 수정 된 배열 (실제로 reduce 함수 내에서 반환해야하는 항목)을 반환하는 반면 push는 푸시 된 값에 액세스 할 수있는 인덱스를 반환합니다. 그 질문에 대답합니까?
sergeyz

분명히이 솔루션은 크롬 (및 노드)에서 매우 빠릅니다. jsperf.com/reduce-for-distinct ES6 버전입니다 : [0,1,2,0,3,2,1,5].reduce((prev, cur) => ~prev.indexOf(cur) ? prev : prev.concat([cur]), []);
Victor Ivens

참고 :이 구현은 NaN친숙 하지 않습니다
Alireza

19

ES6 세트를 사용하여이를 수행 할 수 있습니다.

var duplicatedArray = [1, 2, 3, 4, 5, 1, 1, 1, 2, 3, 4];
var uniqueArray = Array.from(new Set(duplicatedArray));

console.log(uniqueArray);

// 출력은

uniqueArray = [1,2,3,4,5];

17

이 프로토 타입 getUnique은 완전히 정확하지 않습니다. 왜냐하면 내가 다음과 같은 배열을 가지고 있다면 ["1",1,2,3,4,1,"foo"]반환 ["1","2","3","4"]되고 "1"문자열이며1 정수입니다. 그들은 달라요.

올바른 해결책은 다음과 같습니다.

Array.prototype.unique = function(a){
    return function(){ return this.filter(a) }
}(function(a,b,c){ return c.indexOf(a,b+1) < 0 });

사용하여 :

var foo;
foo = ["1",1,2,3,4,1,"foo"];
foo.unique();

위의 내용이 생성 ["1",2,3,4,1,"foo"]됩니다.


1
참고 $foo = 'bar'변수를 선언하는 PHP의 방법입니다. 자바 스크립트로 작동하지만 암시 적 전역을 만들며 일반적으로 수행해서는 안됩니다.
Camilo Martin

@CamiloMartin 죄송하지만 잘못되었습니다. 예는 클로저가 아니며 var 키워드가 없기 때문에 $ foo는 전역입니다. 달러 jsfiddle.net/robaldred/L2MRb
Rob

8
@Rob 그것이 정확히 내가 말하는 바입니다. PHP 사람들은 $foo실제로 var foo는 자바 스크립트에서 변수를 선언하는 방법 이라고 생각할 것 입니다.
Camilo Martin

13

Array.prototype을 확장하지 않거나 (나쁜 습관이라고 함) jquery / underscore를 사용하지 않고 간단히 filter배열을 만들 수 있습니다 .

마지막 발생을 유지함으로써 :

    function arrayLastUnique(array) {
        return array.filter(function (a, b, c) {
            // keeps last occurrence
            return c.indexOf(a, b + 1) < 0;
        });
    },

또는 첫 번째 발생 :

    function arrayFirstUnique(array) {
        return array.filter(function (a, b, c) {
            // keeps first occurrence
            return c.indexOf(a) === b;
        });
    },

Java9 ECMAScript 5 이상이며 IE9 +만을 의미하지만 네이티브 HTML / JS (Windows 스토어 앱, Firefox OS, Sencha, Phonegap, Titanium 등)의 개발에는 좋습니다.


2
js 1.6이라는 사실이 당신이 사용할 수 없다는 것을 의미하지는 않습니다 filter. 상기 MDN 페이지 가 Internet Explorer의 구현을 가지고, 나는, 이전 버전의 브라우저를 의미한다. 또한 JS 1.6은 Firefox의 js 엔진 만 참조하지만 ECMAScript 5라는 것이 옳습니다.
Camilo Martin

@CamiloMartin 1.6을 ECMAScript5로 변경했습니다. 감사.
Cœur

13

마법

a.filter(e=>!(t[e]=e in t)) 

O (n) 성능 ; 배열이 a및에 있다고 가정합니다 t={}. 여기 설명 (+ Jeppe impr.)


14
이것은 너무 멋지다, 견실 한 설명없이 내가 이것을 실행할 때 당신이 내 비트 코인을 채울거야 떨어졌다
Ondřej Želazko

3
내가 의미하는 바는 설명과 해체에 대한 논평으로 답변을 확장해야한다는 것입니다. 사람들이 이와 같은 유용한 답변을 찾을 것이라고 기대하지 마십시오. (실제로는 시원하게
보일지 모르지만

1
@Jeppe 내가 개선을 실행하면 aha 효과가 발생합니다 ( 루프 in이외의 다른 구조 외부에서 연산자 를 사용할 수 있다는 것을 모르기 전에 for: P)-감사합니다-감사합니다. 다른 좋은 답변에 +2를 줄 것입니다 .
Kamil Kiełczewski

2
t필터링 후에도 계속 유지 되는 전역 변수를 만들지 않습니다 ... ??
philipp

1
이것은 정말 까다로운 솔루션입니다. 불행히도 전역 변수를 정의하거나 전역을 숨기려면 모듈 번 들러에 의존하지 않는 한 표현식 외부에서 t를 선언해야합니다. 멋진 것처럼 보이지만 자신과 개발자 팀에게 호의를 베풀고 두 개의 라이너를 작성하십시오. let t = {}; a.filter (e =>! (t [e] = e in t))
ford04

13
[...new Set(duplicates)]

이것은 가장 간단한 것으로 MDN Web Docs 에서 참조됩니다 .

const numbers = [2,3,4,4,2,3,3,4,4,5,5,6,6,7,5,32,3,4,5]
console.log([...new Set(numbers)]) // [2, 3, 4, 5, 6, 7, 32]

이 코드가 문제를 해결하는 방법과 이유에 대한 설명 을 포함하여 질문을 해결할 수는 있지만 게시물의 품질을 향상시키는 데 도움이되고 더 많은 투표를 할 수 있습니다. 지금 질문하는 사람 만이 아니라 앞으로 독자들에게 질문에 대답하고 있음을 기억하십시오. 설명을 추가하기 위해 답을 편집하고 어떤 제한 및 가정이 적용되는지 표시하십시오.
id.ot

11

프로토 타입 프레임 워크를 사용하는 경우 'for'루프를 수행 할 필요가 없으면 다음과 같이 http://www.prototypejs.org/api/array/uniq 를 사용할 수 있습니다 .

var a = Array.uniq();  

중복없이 중복 배열을 생성합니다. 나는 당신의 질문에 걸쳐 배열을 구별하는 방법을 찾고

유니크 ()

나는 사용했다

크기()

그리고 간단한 결과가있었습니다. ps 내가 뭔가 잘못 입력하면 죄송합니다

편집 : 정의되지 않은 레코드를 탈출하려면 추가 할 수 있습니다

콤팩트()

전에 이렇게 :

var a = Array.compact().uniq();  

14
내가 더 나은 답변을 찾았 기 때문에 나는 주제에 대해 생각한 사람뿐만 아니라 모든 사람들을위한 것이라고 생각합니다.
Decebal

11

이제 세트를 사용하여 중복을 제거하고 다시 배열로 변환 할 수 있습니다.

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

console.log([...new Set(names)])

또 다른 해결책은 정렬 및 필터를 사용하는 것입니다

var names = ["Mike","Matt","Nancy", "Matt","Adam","Jenny","Nancy","Carl"];
var namesSorted = names.sort();
const result = namesSorted.filter((e, i) => namesSorted[i] != namesSorted[i+1]);
console.log(result);


10

0JavaScript에서는 잘못된 값 이기 때문 입니다.

this[i] 배열의 값이 0이거나 다른 잘못된 값이면 거짓입니다.


아아, 알았어 .. 지금 볼 수는 있지만 쉽게 작동하게 할 수 있을까요?
Mottie 2009

10
Array.prototype.getUnique = function() {
    var o = {}, a = []
    for (var i = 0; i < this.length; i++) o[this[i]] = 1
    for (var e in o) a.push(e)
    return a
}

배열에 객체 / 배열이 포함되어 있으면 이것이 작동하지 않으며 스칼라 유형을 유지할지 확실하지 않습니다.
Camilo Martin

예, 모든 것이 엄격 해집니다. 평등 비교는 여전히 문자열 방식이지만 (가능한 모든 Javascript 평등 중 너무 불합리한 것은 아니지만) 원래 값을 a o대신 에 저장하여 해결할 수 있습니다 1.
ephemient

Array.prototype은 열거 할 수없는 메소드로만 확장 할 수 있습니다. .... Object.defineProperty (Array.prototype, "getUnique", {}) ... 그러나 헬퍼 오브젝트를 사용한다는 아이디어는 아주 좋습니다
bortunac

10

배열에서 중복 id 속성을 가진 객체를 제거 해야하는 문제가 약간 다릅니다. 이것은 효과가 있었다.

let objArr = [{
  id: '123'
}, {
  id: '123'
}, {
  id: '456'
}];

objArr = objArr.reduce((acc, cur) => [
  ...acc.filter((obj) => obj.id !== cur.id), cur
], []);

console.log(objArr);


9

가장 간단한 대답은 다음과 같습니다.

const array = [1, 1, 2, 2, 3, 5, 5, 2];
const uniqueArray = [...new Set(array)];
console.log(uniqueArray); // [1, 2, 3, 5]

단순하지만 객체 배열에서는 작동하지 않습니다.
Thanwa Ch.

7

가브리엘 Silveira가 왜 그런 식으로 함수를 작성했는지는 잘 모르겠지만 축소 기능을 사용하지 않고 나에게도 효과적인 간단한 양식은 다음과 같습니다.

Array.prototype.unique = function() {
  return this.filter(function(value, index, array) {
    return array.indexOf(value, index + 1) < 0;
  });
};

또는 CoffeeScript에서 :

Array.prototype.unique = ->
  this.filter( (value, index, array) ->
    array.indexOf(value, index + 1) < 0
  )

7

추가 종속성이 괜찮거나 코드베이스에 이미 라이브러리 중 하나가있는 경우 LoDash (또는 밑줄)를 사용하여 배열에서 중복을 제거 할 수 있습니다.

용법

코드베이스에없는 경우 npm을 사용하여 설치하십시오.

npm install lodash

그런 다음 다음과 같이 사용하십시오.

import _ from 'lodash';
let idArray = _.uniq ([
    1,
    2,
    3,
    3,
    3
]);
console.dir(idArray);

밖:

[ 1, 2, 3 ]

7

이것은 많은 답변을 받았지만 내 특정 요구를 해결하지 못했습니다.

많은 답변은 다음과 같습니다.

a.filter((item, pos, self) => self.indexOf(item) === pos);

그러나 복잡한 객체 배열에는 작동하지 않습니다.

다음과 같은 배열이 있다고 가정 해보십시오.

const a = [
 { age: 4, name: 'fluffy' },
 { age: 5, name: 'spot' },
 { age: 2, name: 'fluffy' },
 { age: 3, name: 'toby' },
];

고유 한 이름을 가진 객체를 원하면 다음 array.prototype.findIndex대신 사용해야 합니다 array.prototype.indexOf.

a.filter((item, pos, self) => self.findIndex(v => v.name === item.name) === pos);

훌륭한 해결책은 새로운 배열이 함수에서 반환 될 것이라는 점에주의하십시오. (자체 수정되지 않음)
Thanwa Ch.

6

에서 Shamasis 데브 브 하타 차르 의 블로그 (O (2N) 시간 복잡도) :

Array.prototype.unique = function() {
    var o = {}, i, l = this.length, r = [];
    for(i=0; i<l;i+=1) o[this[i]] = this[i];
    for(i in o) r.push(o[i]);
    return r;
};

에서 폴 아일랜드어 의 블로그 JQuery와에 대한 개선 : .unique():

(function($){

    var _old = $.unique;

    $.unique = function(arr){

        // do the default behavior only if we got an array of elements
        if (!!arr[0].nodeType){
            return _old.apply(this,arguments);
        } else {
            // reduce the array to contain no dupes via grep/inArray
            return $.grep(arr,function(v,k){
                return $.inArray(v,arr) === k;
            });
        }
    };
})(jQuery);

// in use..
var arr = ['first',7,true,2,7,true,'last','last'];
$.unique(arr); // ["first", 7, true, 2, "last"]

var arr = [1,2,3,4,5,4,3,2,1];
$.unique(arr); // [1, 2, 3, 4, 5]

6

간단한 방법으로 고유 한 배열 값 찾기

function arrUnique(a){
  var t = [];
  for(var x = 0; x < a.length; x++){
    if(t.indexOf(a[x]) == -1)t.push(a[x]);
  }
  return t;
}
arrUnique([1,4,2,7,1,5,9,2,4,7,2]) // [1, 4, 2, 7, 5, 9]

6

우리는 Rafael의 답변 을 잃어버린 것으로 보입니다 . 혼합형 배열이없는 경우 이것은 (최소한 2017 년에) 최고의 솔루션이었습니다 .

Array.prototype.getUnique = function(){
    var u = {}, a = [];
    for (var i = 0, l = this.length; i < l; ++i) {
        if (u.hasOwnProperty(this[i])) {
            continue;
        }
        a.push(this[i]);
        u[this[i]] = 1;
    }
return a;
}

당신이 경우 어떻게 혼합 형태의 배열을, 당신은 해시 키를 직렬화 할 수 있습니다 :

Array.prototype.getUnique = function() {
    var hash = {}, result = [], key; 
    for ( var i = 0, l = this.length; i < l; ++i ) {
        key = JSON.stringify(this[i]);
        if ( !hash.hasOwnProperty(key) ) {
            hash[key] = true;
            result.push(this[i]);
        }
    }
    return result;
}

5

당신이 당신의 배열을로드하는 동안 다른 방법으로 주변의 문제를 해결하기 위해서는 중복이없는 것이 유용 할 수 있습니다, 방법의 설정 목적은 그것을 할 것이지만, 아직 모든 브라우저에서 사용할 수 없습니다. 메모리를 절약하고 내용을 여러 번보아야 할 경우 더 효율적입니다.

Array.prototype.add = function (elem) {
   if (this.indexOf(elem) == -1) {
      this.push(elem);
   }
}

견본:

set = [];
[1,3,4,1,2,1,3,3,4,1].forEach(function(x) { set.add(x); });

당신을 제공합니다 set = [1,3,4,2]

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.