배열에서 고유 한 값을 얻는 방법


167

배열에서 고유 한 값 목록을 얻으려면 어떻게해야합니까? 항상 두 번째 배열을 사용해야합니까, 아니면 JavaScript의 java 해시 맵과 비슷한 것이 있습니까?

JavaScriptjQuery 만 사용하려고합니다 . 추가 라이브러리를 사용할 수 없습니다.


2
stackoverflow.com/questions/5381621/…- 내가 원하는 것을 정확하게 설명합니까?
SpaceBison

1
underscore.js도서관 이용에 개방되어 있습니까?
jakee

자바 해시 맵은 기본적으로 자바 스크립트 객체와 동일합니다. 구문은 { "key": "value", "key2": "value2"}
Ian

자바 스크립트 / 타이프 라이터 수집 API는 스칼라에 비해 끔찍한list.toSet
요르단 스튜어트

답변:


120

@Rocket의 답변에 대한 의견에서 계속 진행 했으므로 라이브러리를 사용하지 않는 예를 제공 할 수도 있습니다. 이 두 개의 새로운 프로토 타입 기능을 필요로 contains하고unique

Array.prototype.contains = function(v) {
  for (var i = 0; i < this.length; i++) {
    if (this[i] === v) return true;
  }
  return false;
};

Array.prototype.unique = function() {
  var arr = [];
  for (var i = 0; i < this.length; i++) {
    if (!arr.contains(this[i])) {
      arr.push(this[i]);
    }
  }
  return arr;
}

var duplicates = [1, 3, 4, 2, 1, 2, 3, 8];
var uniques = duplicates.unique(); // result = [1,3,4,2,8]

console.log(uniques);

신뢰성 contains을 높이기 위해 MDN indexOf심으로 교체 하고 각 요소 indexOf가 -1과 같은지 확인할 수 있습니다.


1
~a.indexOf(b) === (a.indexOf(b) == -1)
Orwellophile

1
@Lexynux : 그것이 괴짜 자바 스크립트 대단한 대답이라면 그것이 의미하는 바를 이해하는 사람 만 사용해야하며 그럴 수도 없을 것입니다. 말하는 것은 글쓰기 if (~a.indexOf(b)) ...동일하다는 것입니다 더 길다 것 if (a.indexOf(b) == -1) ...입니다.
Orwellophile

4
이것은 런타임 복잡성이 높습니다 (최악의 경우 : O (n ^ 2))
Rahul Arora

1
이것은 실제로 비효율적 인 구현입니다. 결과 배열에 이미 항목이 포함되어 있는지 확인하는 것은 끔찍합니다. 더 나은 방법 중 하나를 사용하기 객체가 될 것이라고 트랙 카운트, 또는 O에서 일종의 그것은 첫째, 보조 스토리지를 사용 (N N 로그)를 선형 스윕 및 측면 요소에 의해 측면을 비교 싶지 않는 경우
Isaiah Lee

1
"포함"기능이 정말로 필요합니까?
Animesh Kumar

206

또는 단일 라이너 (간단하고 기능적인)를 찾는 사람들에게 현재 브라우저와 호환되는 :

let a = ["1", "1", "2", "3", "3", "1"];
let unique = a.filter((item, i, ar) => ar.indexOf(item) === i);
console.log(unique);

18-04-2017 업데이트

'Array.prototype.includes'가 최신 버전의 기본 브라우저에서 광범위하게 지원되는 것처럼 보입니다 ( 호환성 ).

29-07-2015 업데이트 :

브라우저가 표준화 된 'Array.prototype.includes'메소드를 지원할 계획이 있지만이 질문에 직접 대답하지는 않습니다. 종종 관련이 있습니다.

용법:

["1", "1", "2", "3", "3", "1"].includes("2");     // true

폴리 필 ( 브라우저 지원 , mozilla 소스 ) :

// https://tc39.github.io/ecma262/#sec-array.prototype.includes
if (!Array.prototype.includes) {
  Object.defineProperty(Array.prototype, 'includes', {
    value: function(searchElement, fromIndex) {

      // 1. Let O be ? ToObject(this value).
      if (this == null) {
        throw new TypeError('"this" is null or not defined');
      }

      var o = Object(this);

      // 2. Let len be ? ToLength(? Get(O, "length")).
      var len = o.length >>> 0;

      // 3. If len is 0, return false.
      if (len === 0) {
        return false;
      }

      // 4. Let n be ? ToInteger(fromIndex).
      //    (If fromIndex is undefined, this step produces the value 0.)
      var n = fromIndex | 0;

      // 5. If n ≥ 0, then
      //  a. Let k be n.
      // 6. Else n < 0,
      //  a. Let k be len + n.
      //  b. If k < 0, let k be 0.
      var k = Math.max(n >= 0 ? n : len - Math.abs(n), 0);

      // 7. Repeat, while k < len
      while (k < len) {
        // a. Let elementK be the result of ? Get(O, ! ToString(k)).
        // b. If SameValueZero(searchElement, elementK) is true, return true.
        // c. Increase k by 1.
        // NOTE: === provides the correct "SameValueZero" comparison needed here.
        if (o[k] === searchElement) {
          return true;
        }
        k++;
      }

      // 8. Return false
      return false;
    }
  });
}

케네 벡에서 거의 복사 붙여 넣기를 사용하지만 클로저를 사용하는 대신 배열을 매개 변수로 전달하면 성능이 향상 될 수 있습니다.

-점을 연결하지 않고 단순히 하나의 라이너를 스캔하여 큰 게시물처럼 보였으므로 건너 뛰고 다른 소스를 찾아 다른 사람들이 빨리 찾을 수 있도록 다시 게시했습니다. 즉, 당신의 권리; 케네 벡과 거의 같습니다.
Josh Mc

Nice-필터가 매개 변수로 배열로 전송 된 것을 인식하지 못했고 외부 객체에서 작업하고 싶지 않았습니다. 이것이 바로 내가 필요한 것입니다-내 자바 스크립트 버전 (이전 xerces 버전)에는 잠시 동안 새로운 기능이 없습니다.
Gerard ONeill

1
@GerardONeill 예, 기능적으로 연결되어 있고 .map (...). filter (...)와 같은 변수가 할당되지 않은 배열에 액세스하려는 경우 매우 중요한 상황입니다.
Josh Mc

@ 조쉬 맥, 어떻게 든 '독특한'방법으로 '포함'을 사용할 수 있습니까?
vkelman

143

여기에 포함되지 않은 ES6에 대한 훨씬 깨끗한 솔루션이 있습니다. Setspread 연산자를 사용합니다 ....

var a = [1, 1, 2];

[... new Set(a)]

어떤 반환 [1, 2]


1
너무 영리합니다!
Josh Mc

1
자, 이건 한 라이너입니다!
Mac

11
Typescript에서는 Array.from(... new Set(a))Set을 암시 적으로 배열 유형으로 변환 할 수 없으므로 사용해야 합니다. 그냥 머리!
Zachscs

4
@ Zachscs, 시도했을 때 컴파일 오류가 발생했습니다. 그냥 의미 했습니까 Array.from(new Set(a))? 작동하는 것 같습니다.
adam0101

72

하나의 라이너, 순수한 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 +


4
왜 이것이 투표에 실패했는지 확실하지 않습니다. 처음에는 거의 모호하지 않을 수 있으며 아마도 '영리한' 것으로 분류되어 읽기에는 실용적이지 않지만, 대부분의 다른 답변이 부족한 선언적이고 비파괴 적이며 간결합니다.
Larry

1
@Larry 이것은 몇 년 전에 정확히 동일한 답변이 제공 되었기 때문에 다운 투표되었습니다.
Alex Okrushko

@AlexOkrushko 공정-충분히-형식에 따라 답변을 놓쳤다
Larry

7
한 줄에 모든 것을 넣으면 모든 것이 한 줄짜리입니다 :-)
Gary McGill

등호를 a.indexOf(x) === i세 개의 등호 로 강화하는 것이 좋을 수도 있습니다 .
treejanitor

20

EcmaScript 2016을 사용하면 간단히 이렇게 할 수 있습니다.

 var arr = ["a", "a", "b"];
 var uniqueArray = Array.from(new Set(arr)); // Unique Array ['a', 'b'];

집합은 항상 고유하며 사용 Array.from()하면 집합을 배열로 변환 할 수 있습니다. 참고로 설명서를 살펴보십시오.

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/from https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects /세트


1
대답은 사용해야합니다. indexOf()O (N ^ 2)이므로 답이 끔찍합니다. 스프레드 답변은 괜찮지 만 대형 배열에서는 작동하지 않습니다. 이것이 가장 좋은 방법입니다.
Timmmm

20

이제 ES6에서 새롭게 도입 된 ES6 기능을 사용할 수 있습니다

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

또는 iterables의 Array 확산 구문

let items = [1,1,1,1,3,4,5,2,23,1,4,4,4,2,2,2]; 
let uniqueItems = [...new Set(items)];

고유 한 결과를 반환합니다.

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

1
가장 깨끗한 솔루션!
Dimitris Filippou

이와 new Set같은 기능 을 지원하는 JS 환경 (예 : 최신 Angular / TypeScript)
Don Cheadle

1
Set 및 Map과 같은 iterable에 Array spread 구문을 사용할 수도 있습니다. let items = [1,1,1,1,3,4,5,2,23,1,4,4,4,2,2,2]; let uniqueItems = [...new Set(items)];
jacobedawson

이 ES6 답변을 좋아합니다!
Glen Thompson

1
이것은 @Adeel Imran의 답변과 동일합니다. 기존 답변과 정확히 같은 답변을하지 마십시오.
Timmmm

16

원래 배열을 그대로 두려면

첫 번째의 uniqe 요소를 포함하려면 두 번째 배열이 필요합니다.

대부분의 브라우저에는 Array.prototype.filter다음 이 있습니다 .

var unique= array1.filter(function(itm, i){
    return array1.indexOf(itm)== i; 
    // returns true for only the first instance of itm
});


//if you need a 'shim':
Array.prototype.filter= Array.prototype.filter || function(fun, scope){
    var T= this, A= [], i= 0, itm, L= T.length;
    if(typeof fun== 'function'){
        while(i<L){
            if(i in T){
                itm= T[i];
                if(fun.call(scope, itm, i, T)) A[A.length]= itm;
            }
            ++i;
        }
    }
    return A;
}
 Array.prototype.indexOf= Array.prototype.indexOf || function(what, i){
        if(!i || typeof i!= 'number') i= 0;
        var L= this.length;
        while(i<L){
            if(this[i]=== what) return i;
            ++i;
        }
        return -1;
    }

14

요즘 ES6의 Set 데이터 유형을 사용하여 어레이를 고유 한 세트로 변환 할 수 있습니다. 그런 다음 배열 메소드를 사용해야하는 경우 다시 배열로 변환 할 수 있습니다.

var arr = ["a", "a", "b"];
var uniqueSet = new Set(arr); // {"a", "b"}
var uniqueArr = Array.from(uniqueSet); // ["a", "b"]
//Then continue to use array methods:
uniqueArr.join(", "); // "a, b"

1
깔끔한, 내가 유일한 방법 : 테스트하는 것입니다 말해, 그들은 성능 hickup이 될 수 매우 역동적이고 큰 경우 특히 변환 thosesets 생각, 일부 성능에 번호를 볼 것이 좋을 것이다
우주 비행사

2
트랜스 파일러를 사용 중이거나이를 지원하는 환경에있는 경우 다음과 같이보다 간결하게 동일한 작업을 수행 할 수 있습니다.var uniqueArr = [...new Set(arr)]; // ["a", "b"]
Stenerson

@Astronaut 님이 말씀하신 것처럼 성능에 대해 몇 가지 테스트를 해보셨습니까?
alexventuraio

8

Javascript에서는 네이티브가 아니지만 많은 라이브러리에이 방법이 있습니다.

Underscore.js _.uniq(array)( link )는 꽤 잘 작동합니다 ( source ).


공유해 주셔서 감사합니다! 이 함수는 반복자와 컨텍스트를 v1.4.3의 인수 목록으로 배열과 함께 가져옵니다.
Kunj

6

jQuery를 사용하여 내가 만든 Array 고유 함수는 다음과 같습니다.

Array.prototype.unique = function () {
    var arr = this;
    return $.grep(arr, function (v, i) {
        return $.inArray(v, arr) === i;
    });
}

console.log([1,2,3,1,2,3].unique()); // [1,2,3]

5
핵심 자바 스크립트 객체의 프로토 타입 내에서 jQuery를 사용하려는 경우 $.uniqueArray(arr)? 와 같은 jQuery 함수를 작성하는 것이 좋지 않을 수 있습니다 . 내 jQuery를에 대한 참조를 포함하기 Array'의 프로토 타입은 의심 보인다
jackwanders에게

1
@ jackwanders : 그것에 대해 너무 의심스러운 것은 무엇입니까? 페이지에 jQuery가 있으면 사용하자.
로켓 Hazmat

여러분이 작성한 새로운 고유 함수는 이제 jQuery에 의존합니다. jQuery가 사용 중인지 확인하지 않고 새 사이트 나 앱으로 이동할 수 없습니다.
jackwanders

2
그게 내 요점이었다. jQuery를 사용하려면 함수 자체를 jQuery의 일부로 만드십시오. 핵심 객체의 프로토 타입을 확장하려는 경우, 재사용이 가능하도록 핵심 자바 스크립트를 고수 할 것입니다. 다른 사람이 귀하의 코드를보고 있다면 $.uniqueArrayjQuery에 의존 하는 것이 분명합니다 . 덜 분명합니다 Array.prototype.unique.
jackwanders

1
@ jackwanders : 나는 추측한다. 항상 jQuery를 사용하므로 코드에서 이것을 사용하고 prototypes를 확장하는 것을 좋아 합니다. 그러나 나는 지금 당신의 요점을 이해합니다. 어쨌든 여기에 두겠습니다.
로켓 Hazmat

6

두 번째 배열을 사용하는 짧고 달콤한 솔루션;

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

    var distinct_axes2=[];

    for(var i=0;i<axes2.length;i++)
        {
        var str=axes2[i];
        if(distinct_axes2.indexOf(str)==-1)
            {
            distinct_axes2.push(str);
            }
        }
    console.log("distinct_axes2 : "+distinct_axes2); // distinct_axes2 : 1,4,5,2,3

짧은? 달콤한? 최고의 솔루션을 보셨습니까?
Alex Okrushko

5

빠르고 컴팩트하며 중첩 루프가 없으며 문자열과 숫자뿐만 아니라 모든 객체와 작동하며 술어를 취하며 5 줄의 코드 만 있습니다!

function findUnique(arr, predicate) {
  var found = {};
  arr.forEach(d => {
    found[predicate(d)] = d;
  });
  return Object.keys(found).map(key => found[key]); 
}

예 : 유형별로 고유 한 항목을 찾으려면 다음을 수행하십시오.

var things = [
  { name: 'charm', type: 'quark'},
  { name: 'strange', type: 'quark'},
  { name: 'proton', type: 'boson'},
];

var result = findUnique(things, d => d.type);
//  [
//    { name: 'charm', type: 'quark'},
//    { name: 'proton', type: 'boson'}
//  ] 

마지막이 아닌 첫 번째 고유 항목을 찾으려면 found.hasOwnPropery ()를 추가하십시오.


4

Array.some 및 Array.reduce로 고유 항목을 찾으려면 바닐라 JS 만 필요합니다. ES2015 구문에서는 62 자에 불과합니다.

a.reduce((c, v) => b.some(w => w === v) ? c : c.concat(v)), b)

Array.some 및 Array.reduce는 IE9 + 및 기타 브라우저에서 지원됩니다. ES2015 구문을 지원하지 않는 브라우저에서 지원하도록 일반 기능의 팻 화살표 기능 만 변경하십시오.

var a = [1,2,3];
var b = [4,5,6];
// .reduce can return a subset or superset
var uniques = a.reduce(function(c, v){
    // .some stops on the first time the function returns true                
    return (b.some(function(w){ return w === v; }) ?  
      // if there's a match, return the array "c"
      c :     
      // if there's no match, then add to the end and return the entire array                                        
      c.concat(v)}),                                  
  // the second param in .reduce is the starting variable. This is will be "c" the first time it runs.
  b);                                                 

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/some https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects / 배열 / 축소


4

위의 솔루션의 대부분은 런타임 복잡성이 높습니다.

다음은 O (n) 시간reduce 안에 작업을 수행하고 수행 할 수 있는 솔루션입니다 .

Array.prototype.unique = Array.prototype.unique || function() {
        var arr = [];
	this.reduce(function (hash, num) {
		if(typeof hash[num] === 'undefined') {
			hash[num] = 1; 
			arr.push(num);
		}
		return hash;
	}, {});
	return arr;
}
    
var myArr = [3,1,2,3,3,3];
console.log(myArr.unique()); //[3,1,2];

노트 :

이 솔루션은 축소에 의존하지 않습니다. 아이디어는 객체 맵을 생성하고 고유 한 맵을 배열로 푸시하는 것입니다.



1

당신이 사용할 수있는,

let arr1 = [1,2,1,3];
let arr2 = [2,3,4,5,1,2,3];

let arr3 = [...new Set([...arr1,...arr2])];

그것은 당신에게 독특한 요소를 줄 것입니다,

**> 그러나 캐치가 있습니다.

이 "1"과 1에 대해 diff 요소입니다 **

두 번째 옵션은 배열에서 필터 방법을 사용하는 것입니다.


1

중복으로 배열을 입력 할 수 있으며 아래 메소드는 고유 요소가있는 배열을 반환합니다.

function getUniqueArray(array){
    var uniqueArray = [];
    if (array.length > 0) {
       uniqueArray[0] = array[0];
    }
    for(var i = 0; i < array.length; i++){
        var isExist = false;
        for(var j = 0; j < uniqueArray.length; j++){
            if(array[i] == uniqueArray[j]){
                isExist = true;
                break;
            }
            else{
                isExist = false;
            }
        }
        if(isExist == false){
            uniqueArray[uniqueArray.length] = array[i];
        }
    }
    return uniqueArray;
}

0

지금까지 제공된 솔루션의 유일한 문제는 효율성입니다. 그것에 대해 걱정하고 (그리고 아마도해야 할 경우) 중첩 루프를 피해야합니다 : for * for, filter * indexOf, grep * inArray, 그들은 모두 배열을 여러 번 반복합니다. 당신은 같은 솔루션을 하나의 루프를 구현할 수 있습니다


0
Array.prototype.unique = function () {
    var dictionary = {};
    var uniqueValues = [];
    for (var i = 0; i < this.length; i++) {
        if (dictionary[this[i]] == undefined){
            dictionary[this[i]] = i;
            uniqueValues.push(this[i]);
        }
    }
    return uniqueValues; 
}

0

순수한 JS 에서이 문제를 시도했습니다. 다음 단계를 수행했습니다. 1. 주어진 배열을 정렬합니다. 2. 정렬 된 배열을 반복합니다. 3. 현재 값으로 이전 값과 다음 값을 확인합니다.

// JS
var inpArr = [1, 5, 5, 4, 3, 3, 2, 2, 2,2, 100, 100, -1];

//sort the given array
inpArr.sort(function(a, b){
    return a-b;
});

var finalArr = [];
//loop through the inpArr
for(var i=0; i<inpArr.length; i++){
    //check previous and next value 
  if(inpArr[i-1]!=inpArr[i] && inpArr[i] != inpArr[i+1]){
        finalArr.push(inpArr[i]);
  }
}
console.log(finalArr);

데모


0
function findUniques(arr){
  let uniques = []
  arr.forEach(n => {
    if(!uniques.includes(n)){
      uniques.push(n)
    }       
  })
  return uniques
}

let arr = ["3", "3", "4", "4", "4", "5", "7", "9", "b", "d", "e", "f", "h", "q", "r", "t", "t"]

findUniques(arr)
// ["3", "4", "5", "7", "9", "b", "d", "e", "f", "h", "q", "r", "t"]

0

indexOf요소의 첫 번째 발생을 리턴 한다는 것을 명심 하면 다음과 같이 할 수 있습니다.

Array.prototype.unique = function(){
        var self = this;
        return this.filter(function(elem, index){
            return self.indexOf(elem) === index;
        })
    }


0

이 질문에 대한 또 다른 생각. 적은 코드로 이것을 달성하기 위해 내가 한 일이 있습니다.

var distinctMap = {};
var testArray = ['John', 'John', 'Jason', 'Jason'];
for (var i = 0; i < testArray.length; i++) {
  var value = testArray[i];
  distinctMap[value] = '';
};
var unique_values = Object.keys(distinctMap);

console.log(unique_values);


0

function findUnique(arr) {
  var result = [];
  arr.forEach(function(d) {
    if (result.indexOf(d) === -1)
      result.push(d);
  });
  return result;
}

var unique = findUnique([1, 2, 3, 1, 2, 1, 4]); // [1,2,3,4]
console.log(unique);


0

다음은 equals프리미티브 및 사용자 정의 객체에 사용할 수있는 사용자 정의 기능 이있는 접근 방식입니다 .

Array.prototype.pushUnique = function(element, equalsPredicate = (l, r) => l == r) {
    let res = !this.find(item => equalsPredicate(item, element))
    if(res){
        this.push(element)
    }
    return res
}

용법:

//with custom equals for objects
myArrayWithObjects.pushUnique(myObject, (left, right) => left.id == right.id)

//with default equals for primitives
myArrayWithPrimitives.pushUnique(somePrimitive)

0

내 대답은 고유 한 값을 얻기 위해 사용 Array.filterArray.indexOf방법

array.filter((value, index, self)=>self.indexOf(value)===index)

웹 사이트 에서이 접근법을 보았지만 코드는 여기와 다릅니다. 코드를 한 줄로 단순화하고 여기에 게시하면 누군가가 혜택을 볼 수 있습니다.

참고 : 내 접근 방식은 Josh가 게시 한 라이너와 유사하거나 동일합니다. 변수 이름이 내 코드에 설명되어 있으므로 여기에 남겨두고 있습니다.


-1

중복 검색을 제거하기 위해 선형 검색을 사용할 수 있는지 생각하고있었습니다.

JavaScript:
function getUniqueRadios() {

var x=document.getElementById("QnA");
var ansArray = new Array();
var prev;


for (var i=0;i<x.length;i++)
  {
    // Check for unique radio button group
    if (x.elements[i].type == "radio")
    {
            // For the first element prev will be null, hence push it into array and set the prev var.
            if (prev == null)
            {
                prev = x.elements[i].name;
                ansArray.push(x.elements[i].name);
            } else {
                   // We will only push the next radio element if its not identical to previous.
                   if (prev != x.elements[i].name)
                   {
                       prev = x.elements[i].name;
                       ansArray.push(x.elements[i].name);
                   }
            }
    }

  }

   alert(ansArray);

}

HTML :

<body>

<form name="QnA" action="" method='post' ">

<input type="radio"  name="g1" value="ANSTYPE1"> good </input>
<input type="radio" name="g1" value="ANSTYPE2"> avg </input>

<input type="radio"  name="g2" value="ANSTYPE3"> Type1 </input>
<input type="radio" name="g2" value="ANSTYPE2"> Type2 </input>


<input type="submit" value='SUBMIT' onClick="javascript:getUniqueRadios()"></input>


</form>
</body>

-1

다음은 문제에 대한 하나의 라이너 솔루션입니다.

var seriesValues = [120, 120, 120, 120];
seriesValues = seriesValues.filter((value, index, seriesValues) => (seriesValues.slice(0, index)).indexOf(value) === -1);
console.log(seriesValues);

이것을 브라우저 콘솔에 붙여 넣고 결과를 얻습니다. :-)


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