문제

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

이것이 제가 그것을하는 유일한 방법입니다.

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

이것을 달성하는 더 좋고 간결한 방법이 있습니까?

이것은 스택 오버플로 질문과 매우 밀접한 관련이 있습니다 JavaScript 배열에서 항목을 찾는 가장 좋은 방법? 이는 배열에서 개체를 찾는 것을 다루고 있습니다 indexOf.

도움이 되었습니까?

해결책

현재 브라우저가 있습니다 Array#includes, 무엇을합니다 바로 그거죠 저것, 널리 지원됩니다, 그리고 a 폴리 필 구형 브라우저의 경우.

> ['joe', 'jane', 'mary'].includes('jane');
true 

당신은 또한 사용할 수 있습니다 Array#indexOf, 직접적이지는 않지만 날짜가없는 브라우저에는 폴리 필이 필요하지 않습니다.

jQuery 제안 $.inArray, 기능적으로 동일합니다 Array#indexOf.

aUNDSCORE.JS, JavaScript 유틸리티 라이브러리, 제안 _.contains(list, value), 별명 _.include(list, value), 둘 다 사용합니다 인덱스 내부적으로 JavaScript 배열을 통과 한 경우.

일부 다른 프레임 워크는 비슷한 방법을 제공합니다.

일부 프레임 워크는 이것을 함수로 구현하는 반면 다른 프레임 워크는 기능을 배열 프로토 타입에 추가합니다.

다른 팁

업데이트 : @ORIP가 의견에 언급했듯이 링크 된 벤치 마크는 2008 년에 수행되었으므로 최신 브라우저와 관련이 없을 수 있습니다. 그러나 어쨌든 비 현대식 브라우저를 지원하기 위해서는이 문제가 필요하며 그 이후로 업데이트되지 않았을 것입니다. 항상 자신을 테스트하십시오.

다른 사람들이 말했듯이, 배열을 통한 반복이 아마도 가장 좋은 방법 일 것입니다. 입증되었습니다 그것은 감소하는 것입니다 while 루프는 JavaScript에서 반복하는 가장 빠른 방법입니다. 따라서 다음과 같이 코드를 다시 작성할 수 있습니다.

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

indexOf 어쩌면 "ECMA-262 표준에 대한 JavaScript 확장자 일 수도 있습니다. 따라서 표준의 다른 구현에는 존재하지 않을 수 있습니다."

예시:

[1, 2, 3].indexOf(1) => 0
["foo", "bar", "baz"].indexOf("bar") => 1
[1, 2, 3].indexOf(4) => -1

afaics 마이크로 소프트 ~ 아니다 일종의 대안을 제공합니다 이에는 인터넷 익스플로러 (및 지원하지 않는 기타 브라우저의 배열에 유사한 기능을 추가 할 수 있습니다. indexOf) 원한다면, a 빠른 Google 검색이 공개됩니다 (예를 들어, 이 하나).

ECMAScript 7 소개 Array.prototype.includes.

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

[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

같지 않은 indexOf, 사용하는 엄격한 평등 비교, includes 사용 비교 Samevaluezero 평등 알고리즘. 즉, 배열에 A가 포함 된 경우 감지 할 수 있음을 의미합니다. NaN:

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

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

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

현재는 여전히 초안이지만 가능합니다 폴리 채식 모든 브라우저에서 작동합니다.

b 가치입니다 a 배열입니다. 돌아옵니다 true 또는 false:

function(a, b) {
    return a.indexOf(b) != -1
}

상단 답변은 원시 유형을 가정하지만 배열에 특성이있는 객체가 포함되어 있는지 확인하려면 Array.prototype.some () 매우 우아한 해결책입니다.

const items = [ {a: '1'}, {a: '2'}, {a: '3'} ]

items.some(item => item.a === '3')  // returns true
items.some(item => item.a === '4')  // returns false

그것에 대한 좋은 점은 요소가 발견되면 반복이 중단되므로 불필요한 반복주기가 저장되었다는 것입니다.

또한, 그것은 잘 맞습니다 if 부울을 반환하기 때문에 진술 :

if (items.some(item => item.a === '3')) {
  // do something
}

* Jamess가 2018 년 9 월 현재 의견에서 지적한 것처럼 Array.prototype.some() 완전히 지원됩니다 : caniuse.com 지원 테이블

여기에 있습니다 JavaScript 1.6 호환 구현 Array.indexOf:

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;
        };
}

사용:

function isInArray(array, search)
{
    return array.indexOf(search) >= 0;
}

// Usage
if(isInArray(my_array, "my_value"))
{
    //...
}

JavaScript 확장 Array 객체는 새로운 속성 (사용자 정의 방법)을 for-in 기존 스크립트를 깨뜨릴 수있는 루프. 몇 년 전 저자의 저자 원기 도서관은 이런 종류의 것을 제거하기 위해 라이브러리 구현을 리엔지니어링해야했습니다.

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

상자를 잠시 생각하면,이 전화를 여러 번 만들고 있다면 사용하는 것이 훨씬 더 효율적입니다. 연관 배열 해시 함수를 사용하여 조회를 수행하는 맵.

https://developer.mozilla.org/en-us/docs/web/javascript/reference/global_objects/map

짧막 한 농담:

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

다음을 사용합니다.

Array.prototype.contains = function (v) {
    return this.indexOf(v) > -1;
}

var a = [ 'foo', 'bar' ];

a.contains('foo'); // true
a.contains('fox'); // false
function contains(a, obj) {
    return a.some(function(element){return element == obj;})
}

Array.prototype.some () 5 판에서 ECMA-262 표준에 추가되었습니다.

희망적으로 더 빠른 양방향 indexOf / lastIndexOf 대안

2015

새로운 방법으로 포함 매우 좋습니다. 현재 지원은 기본적으로 0입니다.

느린 인덱스/lastindexof 함수를 대체 할 방법을 생각하고 있었던 것은 오랜 시간입니다.

최고의 답변을 보면서 성능적인 방식이 이미 발견되었습니다. 내가 선택한 사람들로부터 contains @damir Zekic에 의해 게시 된 기능. 그러나 벤치 마크는 2008 년부터 구식이라고 말합니다.

나도 선호합니다 while ~ 위에 for, 그러나 특정한 이유가 아니기 때문에 나는 for loop으로 함수를 쓰는 것을 끝냈습니다. a while --.

배열을하는 동안 배열의 양쪽을 확인하면 반복이 훨씬 느려 있는지 궁금했습니다. 분명히 아니요, 따라서이 기능은 최상위 투표보다 약 2 배 빠릅니다. 분명히 그것은 또한 원주민보다 빠릅니다. 이것은 당신이 검색하는 값이 배열의 시작 또는 끝에 있는지 알지 못하는 실제 환경에서.

당신이 방금 값으로 배열을 밀었을 때, lastIndexof를 사용하는 것은 아마도 최상의 솔루션 일 것입니다. 그러나 큰 배열을 여행해야하고 결과가 어디에나있을 수 있다면, 이것은 물건을 더 빨리 만들기위한 견고한 솔루션이 될 수 있습니다.

양방향 지수/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 항목이있는 배열을 만들었습니다.

세 가지 쿼리 : 처음, 배열의 중간 및 끝에.

나는 당신이 이것을 흥미롭고 공연을 테스트하기를 바랍니다.

참고 : 보시다시피 나는 약간 수정했습니다. contains indexof & lastindexof 출력을 반영하는 기능 (기본적으로 true 이랑 index 그리고 false ~와 함께 -1). 그것은 그것을 해치지 않아야합니다.

배열 프로토 타입 변형

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');

함수는 참 또는 거짓 또는 객체, 문자열 또는 그 밖의 모든 것을 반환하도록 쉽게 수정할 수 있습니다.

그리고 여기에 있습니다 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');

이것이 어떻게 가능한지?

배열에서 반사 된 인덱스를 얻는 간단한 계산은 너무 간단하여 실제 루프 반복을 수행하는 것보다 두 배 더 빠릅니다.

다음은 반복 당 세 가지 검사를 수행하는 복잡한 예는 있지만, 이는 더 긴 계산으로 만 가능하여 코드의 둔화를 유발합니다.

http://jsperf.com/bidirectionalindexof/2

JavaScript 1.6 이상 (Firefox 1.5 이상)을 사용하는 경우 사용할 수 있습니다. Array.indexof. 그렇지 않으면, 나는 당신이 당신의 원래 코드와 비슷한 것으로 끝날 것이라고 생각합니다.

배열에 객체가 존재하는지 반복적으로 확인하는 경우 아마도 조사해야합니다.

  1. 배열을 항상 정렬하여 유지합니다 삽입 정렬 배열에서 (올바른 장소에 새 개체를 넣음)
  2. remove+정렬 삽입 삽입 작업으로 객체를 업데이트하고
  3. a 이진 검색 당신의 조회 contains(a, obj).
function inArray(elem,array)
{
    var len = array.length;
    for(var i = 0 ; i < len;i++)
    {
        if(array[i] == elem){return i;}
    }
    return -1;
} 

찾은 경우 배열 인덱스를 반환하거나 찾을 수없는 경우 -1

우리는이 스 니펫을 사용합니다 (물체, 배열, 문자열과 함께 작동) :

/*
 * @function
 * @name Object.prototype.inArray
 * @description Extend Object prototype within inArray function
 *
 * @param {mix}    needle       - Search-able needle
 * @param {bool}   searchInKey  - Search needle in keys?
 *
 */
Object.defineProperty(Object.prototype, 'inArray',{
    value: function(needle, searchInKey){

        var object = this;

        if( Object.prototype.toString.call(needle) === '[object Object]' || 
            Object.prototype.toString.call(needle) === '[object Array]'){
            needle = JSON.stringify(needle);
        }

        return Object.keys(object).some(function(key){

            var value = object[key];

            if( Object.prototype.toString.call(value) === '[object Object]' || 
                Object.prototype.toString.call(value) === '[object Array]'){
                value = JSON.stringify(value);
            }

            if(searchInKey){
                if(value === needle || key === needle){
                return true;
                }
            }else{
                if(value === needle){
                    return true;
                }
            }
        });
    },
    writable: true,
    configurable: true,
    enumerable: false
});

용법:

var a = {one: "first", two: "second", foo: {three: "third"}};
a.inArray("first");          //true
a.inArray("foo");            //false
a.inArray("foo", true);      //true - search by keys
a.inArray({three: "third"}); //true

var b = ["one", "two", "three", "four", {foo: 'val'}];
b.inArray("one");         //true
b.inArray('foo');         //false
b.inArray({foo: 'val'})   //true
b.inArray("{foo: 'val'}") //false

var c = "String";
c.inArray("S");        //true
c.inArray("s");        //false
c.inArray("2", true);  //true
c.inArray("20", true); //false

Lodash를 사용하십시오 약간 기능.

간결하고 정확하며 크로스 플랫폼 지원이 뛰어납니다.

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

요구 사항 : JavaScript 배열에 객체가 포함되어 있는지 확인하는 가장 간결하고 효율적인 방법을 권장합니다.

받아 들여진 답변 :

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

내 추천 :

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

메모:

$ .inarray는 a 스칼라 값은 스칼라 배열에 존재합니다 ...

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

... 그러나 질문은 물체 배열에 포함되어 있습니다.

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

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

모든 현대식 브라우저에서 작동하는 솔루션 :

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.indexOf 그리고 Array.includes (여기서 대부분의 답변뿐만 아니라)는 값이 아니라 참조로만 비교합니다.

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

보너스

최적화되지 않은 ES6 1 라이너 :

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

참고 : 키가 동일한 순서 인 경우 객체를 값으로 비교하는 것이 더 잘 작동하므로 안전하기 위해서는 이와 같은 패키지로 키를 먼저 정렬 할 수 있습니다. https://www.npmjs.com/package/sort-keys


업데이트 contains Perf 최적화로 기능합니다. 감사 itinance 그것을 지적하기 위해.

하는 동안 array.indexOf(x)!=-1 이 작업을 수행하는 가장 간결한 방법이며 (그리고 10 년 이상 비 인테르 탐색기 브라우저에서 지원을 받았습니다 ...), O (1)가 아니라 O (n)은 끔찍합니다. 배열이 변경되지 않으면 배열을 해시 가능로 변환 할 수 있습니다. table[x]!==undefined 또는 ===undefined:

Array.prototype.toTable = function() {
    var t = {};
    this.forEach(function(x){t[x]=true});
    return t;
}

데모:

var toRemove = [2,4].toTable();
[1,2,3,4,5].filter(function(x){return toRemove[x]===undefined})

(불행히도, 배열을 만들 수는 있지만 배열을 "동결"하고 hashtable을 this._cache를 두 줄로 보관할 수 있지만 나중에 배열을 편집하기로 선택하면 잘못된 결과를 얻을 수 있습니다. JavaScript는 후크가 충분하지 않습니다. 예를 들어 파이썬과 달리이 상태를 유지하겠습니다.)

ECMAScript 6에는 찾기에 대한 우아한 제안이 있습니다.

찾기 메소드는 콜백이 실제 값을 반환하는 곳을 찾을 때까지 배열에있는 각 요소에 대해 콜백 함수를 한 번 실행합니다. 그러한 요소가 발견되면 해당 요소의 값을 즉시 반환합니다. 그렇지 않으면, 찾기 반품을 정의하지 않습니다. 콜백은 값을 할당 한 배열의 인덱스에 대해서만 호출됩니다. 삭제되었거나 값이 할당되지 않은 인덱스에 대해서는 호출되지 않습니다.

여기에 있습니다 MDN 문서 그것에.

찾기 기능은 다음과 같이 작동합니다.

function isPrime(element, index, array) {
    var start = 2;
    while (start <= Math.sqrt(element)) {
        if (element % start++ < 1) return false;
    }
    return (element > 1);
}

console.log( [4, 6, 8, 12].find(isPrime) ); // Undefined, not found
console.log( [4, 5, 8, 12].find(isPrime) ); // 5

이것을 ECMAScript 5 이하에서 사용할 수 있습니다. 함수 정의.

if (!Array.prototype.find) {
  Object.defineProperty(Array.prototype, 'find', {
    enumerable: false,
    configurable: true,
    writable: true,
    value: function(predicate) {
      if (this == null) {
        throw new TypeError('Array.prototype.find called on null or undefined');
      }
      if (typeof predicate !== 'function') {
        throw new TypeError('predicate must be a function');
      }
      var list = Object(this);
      var length = list.length >>> 0;
      var thisArg = arguments[1];
      var value;

      for (var i = 0; i < length; i++) {
        if (i in list) {
          value = list[i];
          if (predicate.call(thisArg, value, i, list)) {
            return value;
          }
        }
      }
      return undefined;
    }
  });
}

사용:

var myArray = ['yellow', 'orange', 'red'] ;

alert(!!~myArray.indexOf('red')); //true

데모

정확히 무엇을 아는 것 tilde ~ 이 시점 에서이 질문을 참조하십시오 틸데는 표현보다 우선 할 때 무엇을합니까?.

방법은 다음과 같습니다 프로토 타입이 그렇게합니다:

/**
 *  Array#indexOf(item[, offset = 0]) -> Number
 *  - item (?): A value that may or may not be in the array.
 *  - offset (Number): The number of initial items to skip before beginning the
 *      search.
 *
 *  Returns the position of the first occurrence of `item` within the array &mdash; or
 *  `-1` if `item` doesn't exist in the array.
**/
function indexOf(item, i) {
  i || (i = 0);
  var length = this.length;
  if (i < 0) i = length + i;
  for (; i < length; i++)
    if (this[i] === item) return i;
  return -1;
}

또한 참조하십시오 여기 그들이 그것을 연결하는 방법에 대해.

좋아, 당신은 그냥 할 수 있습니다 최적화하십시오 결과를 얻기위한 코드!

더 깨끗하고 더 나은이 작업을 수행하는 방법에는 여러 가지가 있지만 패턴을 얻고 사용에 적용하고 싶었습니다. JSON.stringify, 단순히 당신의 경우에 이런 일을하십시오.

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

사용:

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);
}

나는 그것이 가장 좋은 방법이 아니라는 것을 알고 있지만, 객체들 사이를 상호 작용하는 기본 Icomponday 방법이 없기 때문에 배열에서 두 엔티티를 비교할 수있는만큼 가깝다고 생각합니다. 또한, 배열 객체를 확장하는 것은 현명한 일이 아닐 수도 있지만 때로는 괜찮습니다 (당신이 그것을 알고 있다면 트레이드 오프).

하나는 사용할 수 있습니다 세트 "has ()"방법이 있습니다.

function contains(arr, obj) {
  var proxy = new Set(arr);
  if (proxy.has(obj))
    return true;
  else
    return false;
}

var arr = ['Happy', 'New', 'Year'];
console.log(contains(arr, 'Happy'));

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

var arrayContains = function(object) {
  return (serverList.filter(function(currentObject) {
    if (currentObject === object) {
      return currentObject
    }
    else {
      return false;
    }
  }).length > 0) ? true : false
}
  1. 어느 쪽이든 Array.indexOf(Object).
  2. ECMA 7을 사용하면 사용할 수 있습니다 Array.includes(Object).
  3. ECMA 6을 사용하면 사용할 수 있습니다 Array.find(FunctionName) 어디 FunctionName 배열에서 객체를 검색하는 사용자 정의 함수입니다.

    도움이 되었기를 바랍니다!

비슷한 점 : "Search Lambda"로 첫 번째 요소를 찾습니다.

Array.prototype.find = function(search_lambda) {
  return this[this.map(search_lambda).indexOf(true)];
};

용법:

[1,3,4,5,8,3,5].find(function(item) { return item % 2 == 0 })
=> 4

커피 스크립트에서도 마찬가지 :

Array.prototype.find = (search_lambda) -> @[@map(search_lambda).indexOf(true)]
라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top