배열에 JavaScript로 객체가 포함되어 있는지 확인하려면 어떻게합니까?



14 Answers

업데이트 : @orip은 주석에서 언급 했으므로 2008 년에 링크 된 벤치 마크가 수행되었으므로 최신 브라우저에서는 결과가 적절하지 않을 수 있습니다. 그러나 어쨌든 비 현대적인 브라우저를 지원하려면이 기능이 필요하며 이후로 업데이트되지 않았을 것입니다. 항상 스스로 테스트 해보십시오.

다른 사람들이 말했듯이 배열을 통한 반복이 가장 좋은 방법 일 수 있지만 JavaScript에서 반복 while 루프가 가장 빠른 방법 이라고 입증되었습니다 . 따라서 다음과 같이 코드를 다시 작성해야 할 수 있습니다.

function contains(a, obj) {
    var i = a.length;
    while (i--) {
       if (a[i] === obj) {
           return true;
       }
    }
    return false;
}

물론 배열 프로토 타입을 확장 할 수도 있습니다.

Array.prototype.contains = function(obj) {
    var i = this.length;
    while (i--) {
        if (this[i] === obj) {
            return true;
        }
    }
    return false;
}

이제 다음과 같이 간단하게 사용할 수 있습니다.

alert([1, 2, 3].contains(2)); // => true
alert([1, 2, 3].contains('2')); // => false
Question

JavaScript 배열에 객체가 포함되어 있는지 확인하는 가장 간결하고 효율적인 방법은 무엇입니까?

이것이 내가 아는 유일한 방법이다.

function contains(a, obj) {
    for (var i = 0; i < a.length; i++) {
        if (a[i] === obj) {
            return true;
        }
    }
    return false;
}

이 작업을 수행하는 더 우수하고 간결한 방법이 있습니까?

질문과 매우 밀접하게 관련 되어 있습니다 JavaScript Array에서 항목을 찾는 가장 좋은 방법은 무엇입니까? indexOf 사용하여 배열에서 객체를 찾는 문제를 해결합니다.




희망보다 빠른 양방향 indexOf / lastIndexOf 대안

2015

새로운 메소드가 array.includes(value) 있지만, 지원은 기본적으로 현재는 0입니다.

느린 indexOf / lastIndexOf 함수를 대체 할 길을 생각하고 있습니다.

공연자의 길은 이미 발견되었고, 가장 많이 찾는 답을 보았습니다. 그 중에서 내가 가장 빨리해야 할 @Damir Zekic이 게시 한 contains 함수를 선택했습니다. 그러나 그것은 또한 벤치 마크가 2008 년에 나온 것이기 때문에 구식이라고합니다.

나는 또한 while 이상 for 선호하지만 특정 이유가 없으면 for 루프를 사용하여 함수를 작성하지 못했습니다. 그것도 while -- 할 수 있습니다 while -- .

배열을 수행하는 동안 배열의 양쪽을 검사하면 반복이 훨씬 느려지는지 궁금했습니다. 외관상으로는 아니오, 그래서이 기능은 투표 된 것보다 약 2 배 빠릅니다. 분명히 네이티브 것보다 빠릅니다. 실제 환경에서, 검색중인 값이 배열의 처음 또는 끝에 있는지 여부를 모를 경우.

lastIndexOf를 사용하는 배열을 방금 밀어 넣었 음을 알았을 때 아마도 가장 좋은 솔루션으로 남아 있지만 큰 배열을 거쳐야 만하고 결과가 모든 곳에서 발생할 수 있다면 일을 더 빨리 수행 할 수있는 견고한 솔루션이 될 수 있습니다.

양방향 indexOf / lastIndexOf

function bidirectionalIndexOf(a, b, c, d, e){
  for(c=a.length,d=c*1; c--; ){
    if(a[c]==b) return c; //or this[c]===b
    if(a[e=d-1-c]==b) return e; //or a[e=d-1-c]===b
  }
  return -1
}

//Usage
bidirectionalIndexOf(array,'value');

성능 검사

http://jsperf.com/bidirectionalindexof

테스트 할 때 100k 항목이있는 배열을 만들었습니다.

세 가지 질의 : 배열의 시작, 중간 및 끝.

이 흥미로운 것을 발견하고 성능을 시험해 보시기 바랍니다.

참고 : 보시다시피 indexOf 및 lastIndexOf 출력을 반영하도록 contains 함수를 약간 수정했습니다 (기본적으로 index 에서는 false 이고 -1 false ). 그건 그걸 해치지 않아야 해.

배열 프로토 타입 변형

Object.defineProperty(Array.prototype,'bidirectionalIndexOf',{value:function(b,c,d,e){
  for(c=this.length,d=c*1; c--; ){
    if(this[c]==b) return c; //or this[c]===b
    if(this[e=d-1-c] == b) return e; //or this[e=d-1-c]===b
  }
  return -1
},writable:false, enumerable:false});

// Usage
array.bidirectionalIndexOf('value');

true 또는 false 또는 객체, 문자열 또는 무엇이든지 반환하도록 함수를 쉽게 수정할 수도 있습니다.

그리고 여기 while 변종이 있습니다 :

function bidirectionalIndexOf(a, b, c, d){
  c=a.length; d=c-1;
  while(c--){
    if(b===a[c]) return c;
    if(b===a[d-c]) return d-c;
  }
  return c
}

// Usage
bidirectionalIndexOf(array,'value');

이것이 어떻게 가능한지?

배열에서 반사 된 인덱스를 얻는 간단한 계산은 너무 간단하므로 실제 루프 반복을 수행하는 것보다 2 배 빠르다고 생각합니다.

반복마다 세 번씩 수행하는 복잡한 예제가 있지만 코드의 속도 저하를 초래하는 더 긴 계산에서만 가능합니다.

http://jsperf.com/bidirectionalindexof/2




Array.indexOfJavaScript 1.6 호환 구현은 다음과 같습니다.

if (!Array.indexOf)
{
  Array.indexOf = [].indexOf ?
      function (arr, obj, from) { return arr.indexOf(obj, from); }:
      function (arr, obj, from) { // (for IE6)
        var l = arr.length,
            i = from ? parseInt( (1*from) + (from<0 ? l:0), 10) : 0;
        i = i<0 ? 0 : i;
        for (; i<l; i++) {
          if (i in arr  &&  arr[i] === obj) { return i; }
        }
        return -1;
      };
}



JavaScript 1.6 이상 (Firefox 1.5 이상)을 사용하는 경우 Array.indexOf 를 사용할 수 있습니다. 그렇지 않으면 원래 코드와 비슷한 것으로 끝날 것입니다.




lodash의 some 기능을 사용하십시오.

간결하고 정확하며 훌륭한 크로스 플랫폼을 지원합니다.

허용 된 답변은 요구 사항을 충족하지 못합니다.

요구 사항 : 자바 스크립트 배열에 객체가 포함되어 있는지 확인하는 가장 간결하고 효율적인 방법을 제안하십시오.

수락 된 답변 :

$.inArray({'b': 2}, [{'a': 1}, {'b': 2}])
> -1

내 추천 :

_.some([{'a': 1}, {'b': 2}], {'b': 2})
> true

노트:

$ .inArray는 스칼라 배열에 스칼라 값이 존재하는지 여부를 결정하는데 잘 작동합니다 ...

$.inArray(2, [1,2])
> 1

...하지만 질문은 분명히 개체 가 배열에 포함되어 있는지 확인하는 효율적인 방법을 요구합니다.

스칼라와 객체를 모두 처리하려면 다음을 수행 할 수 있습니다.

(_.isObject(item)) ? _.some(ary, item) : (_.indexOf(ary, item) > -1)



다른 사람들이 언급했듯이 Array.indexOf 를 사용할 수 있지만 모든 브라우저에서 사용할 수있는 것은 아닙니다. https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Array/indexOf 의 코드는 이전 브라우저에서도 동일하게 작동합니다.

indexOf는 최근 ECMA-262 표준에 추가되었습니다. 따라서 모든 브라우저에 존재하지 않을 수 있습니다. 스크립트의 시작 부분에 다음 코드를 삽입하여이 문제를 해결할 수 있습니다. 기본적으로 지원하지 않는 구현에서 indexOf를 사용할 수 있습니다. 이 알고리즘은 Object, TypeError, Number, Math.floor, Math.abs 및 Math.max가 원래 값을 가진다고 가정하고 ECMA-262, 5th edition에 명시된 알고리즘과 동일합니다.

if (!Array.prototype.indexOf) {
    Array.prototype.indexOf = function (searchElement /*, fromIndex */ ) {
        "use strict";
        if (this == null) {
            throw new TypeError();
        }
        var t = Object(this);
        var len = t.length >>> 0;
        if (len === 0) {
            return -1;
        }
        var n = 0;
        if (arguments.length > 1) {
            n = Number(arguments[1]);
            if (n != n) { // shortcut for verifying if it's NaN
                n = 0;
            } else if (n != 0 && n != Infinity && n != -Infinity) {
                n = (n > 0 || -1) * Math.floor(Math.abs(n));
            }
        }
        if (n >= len) {
            return -1;
        }
        var k = n >= 0 ? n : Math.max(len - Math.abs(n), 0);
        for (; k < len; k++) {
            if (k in t && t[k] === searchElement) {
                return k;
            }
        }
        return -1;
    }
}



  1. Array.indexOf (Object)를 사용하십시오.
  2. ECMA 7을 사용하면 Array.includes (Object)를 사용할 수 있습니다.
  3. ECMA 6에서는 Array.find (FunctionName)을 사용할 수 있습니다. 여기서 FunctionName은 배열에서 객체를 검색하는 사용자 정의 함수입니다.

    희망이 도움이!




JavaScript Array 객체를 확장하는 것은 기존의 스크립트를 손상시킬 수있는 for-in 루프에 새로운 속성 (사용자 정의 메서드)을 도입했기 때문에 정말 나쁜 생각입니다. 몇 년 전에 Prototype 라이브러리의 저자는 이런 종류의 것을 제거하기 위해 라이브러리 구현을 다시 엔지니어링해야했습니다.

페이지에서 실행중인 다른 JavaScript와의 호환성에 대해 걱정할 필요가 없다면, 그렇지 않으면 더 어색하지만 안전한 독립형 기능 솔루션을 권합니다.




function inArray(elem,array)
{
    var len = array.length;
    for(var i = 0 ; i < len;i++)
    {
        if(array[i] == elem){return i;}
    }
    return -1;
} 

발견되면 배열 인덱스를 반환하고, 발견되지 않으면 -1을 반환합니다.




용도:

Array.prototype.contains = function(x){
  var retVal = -1;

  // x is a primitive type
  if(["string","number"].indexOf(typeof x)>=0 ){ retVal = this.indexOf(x);}

  // x is a function
  else if(typeof x =="function") for(var ix in this){
    if((this[ix]+"")==(x+"")) retVal = ix;
  }

  //x is an object...
  else {
    var sx=JSON.stringify(x);
    for(var ix in this){
      if(typeof this[ix] =="object" && JSON.stringify(this[ix])==sx) retVal = ix;
    }
  }

  //Return False if -1 else number if numeric otherwise string
  return (retVal === -1)?false : ( isNaN(+retVal) ? retVal : +retVal);
}

나는 그것이가는 가장 좋은 방법은 아니지만 객체간에 상호 작용할 수있는 고유 한 IComparable 방법이 없기 때문에 이것은 배열에서 두 엔티티를 비교할 수있는만큼 가깝습니다. 또한, Array 객체를 확장하는 것이 현명한 방법이 아닌 경우도 있지만, 때로는 괜찮습니다 (잘 알고있는 경우).




최신의 모든 브라우저에서 작동하는 솔루션 :

function contains(arr, obj) {
  const stringifiedObj = JSON.stringify(obj); // Cache our object to not call `JSON.stringify` on every iteration
  return arr.some(item => JSON.stringify(item) === stringifiedObj);
}

용법:

contains([{a: 1}, {a: 2}], {a: 1}); // true

IE6 + 솔루션 :

function contains(arr, obj) {
  var stringifiedObj = JSON.stringify(obj)
  return arr.some(function (item) {
    return JSON.stringify(item) === stringifiedObj;
  });
}

// .some polyfill, not needed for IE9+
if (!('some' in Array.prototype)) {
  Array.prototype.some = function (tester, that /*opt*/) {
    for (var i = 0, n = this.length; i < n; i++) {
      if (i in this && tester.call(that, this[i], i, this)) return true;
    } return false;
  };
}

용법:

contains([{a: 1}, {a: 2}], {a: 1}); // true

JSON.stringify 를 사용하는 이유는 무엇입니까?

Array.indexOfArray.includes (여기에서 대부분의 답변뿐만 아니라)는 값이 아닌 참조로만 비교됩니다.

[{a: 1}, {a: 2}].includes({a: 1});
// false, because {a: 1} is a new object

보너스

최적화되지 않은 ES6 one-liner :

[{a: 1}, {a: 2}].some(item => JSON.stringify(item) === JSON.stringify({a: 1));
// true

참고 : 키를 같은 순서로 사용하면 개체를 값으로 비교하면 안전합니다. 먼저 다음과 같은 패키지로 키를 정렬 할 수 있습니다. https://www.npmjs.com/package/sort-keys

perf 최적화로 contains 함수를 업데이트했습니다. 그것을 지적 해 주셔서 감사합니다.




짧막 한 농담:

function contains(arr, x) {
    return arr.filter(function(elem) { return elem == x }).length > 0;
}



이 트릭을 사용할 수도 있습니다.

var arrayContains = function(object) {
  return (serverList.filter(function(currentObject) {
    if (currentObject === object) {
      return currentObject
    }
    else {
      return false;
    }
  }).length > 0) ? true : false
}






ECMAScript 7은 array.includes(value) 도입했습니다.

다음과 같이 사용할 수 있습니다.

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

또한 두 번째 인수 fromIndex 선택적으로 사용할 수 있습니다.

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

Strict Equality Comparison 을 사용하는 indexOf 와는 달리 SameValueZero 동등 알고리즘을 사용하여 비교합니다. 즉, 배열에 NaN 포함되어 있는지 감지 할 수 있습니다.

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

또한 indexOf 와는 달리 indexOf includes 누락 된 인덱스를 건너 뛰지 않습니다.

new Array(5).includes(undefined); // true

현재는 여전히 초안이지만 모든 브라우저에서 작동하도록 polyfill 될 수 있습니다.




Related