객체 배열의 indexOf 메소드?


512

객체를 포함하는 배열의 인덱스를 얻는 가장 좋은 방법은 무엇입니까?

이 시나리오를 상상해보십시오.

var hello = {
    hello: 'world',
    foo: 'bar'
};
var qaz = {
    hello: 'stevie',
    foo: 'baz'
}

var myArray = [];
myArray.push(hello,qaz);

이제이 예제에서 indexOf어떤 hello속성이 'stevie'어떤 객체인지 확인 하고 싶습니다 1.

나는 JavaScript를 처음 접하는 초보자이며 간단한 방법이 있는지 또는 그렇게하기 위해 내 자신의 함수를 만들어야하는지 모르겠습니다.


1
당신은 두 개체 병합 하시겠습니까 hello과를 qaz?
Armin

아뇨 배열에 객체 목록을 갖고 싶습니다.
Antonio Laguna

아 알았어! 정의 된 속성이있는 배열에서 전체 객체의 위치를 ​​알고 싶습니다.
Armin

10
이 SO 답변 으로이 정확한 문제를 해결하는 매우 간단한 기능을 찾았습니다. var elementPos = array.map(function(x) {return x.id; }).indexOf(idYourAreLookingFor); var objectFound = array[elementPos]; [link] ( stackoverflow.com/a/16100446/1937255 )
Rick

ES6 Array.indexOf가 허용 된 답변보다 낫습니다 (ES6이 효과가있는 경우)-아래의 전체 예를 참조하십시오
yar1

답변:


1043

map 함수를 사용하여 한 줄로 해결할 수 있다고 생각합니다 .

pos = myArray.map(function(e) { return e.hello; }).indexOf('stevie');

58
이것은 정직하게 받아 들여지는 대답이어야합니다. 대부분의 브라우저는 현재 지원Array.prototype.map()
AlbertEngelB

10
IE8에서는 지원되지 않지만 문제가되지 않으면 이것이 최선의 해결책입니다.
안토니오 라구나

57
음 ... Array.prototype.map ()은 매핑 된 항목을 포함하는 완전히 새로운 배열을 생성한다는 점에 주목할 가치가 있습니까? 따라서 1000 개의 요소가있는 배열이 있다면 먼저 1000 개의 요소로 다른 배열을 만든 다음 검색합니까? 이 방법의 성능과 간단한 for 루프를 비교해 볼 가치가 있다고 생각합니다. 특히 리소스가 제한된 모바일 플랫폼에서 실행중인 경우.
Doug

7
@Doug 성능에 대한 요점은 맞지만 병목 현상이 발생할 때까지 IO / 네트워크에 거의 정의 된 응용 프로그램의 경우 한 줄의 코드를 7 개로 바꾸는 사람은 누구입니까?
Jared Smith

6
기술적으로 축소 된 JS 파일은 한 줄도이며, D
greaterKing

371

Array.prototype.findIndex 는 IE 이외의 모든 브라우저에서 지원됩니다 (에지 없음). 그러나 제공된 폴리 필 은 훌륭합니다.

var indexOfStevie = myArray.findIndex(i => i.hello === "stevie");

지도가있는 솔루션은 괜찮습니다. 그러나 모든 검색마다 전체 배열을 반복합니다. 일치하는 것이 발견되면 반복을 중지 하는 findIndex 의 최악의 경우입니다 .


간결한 방법은 없지만 (개발자가 IE8에 대해 걱정해야 할 때) 일반적인 해결책은 다음과 같습니다.

var searchTerm = "stevie",
    index = -1;
for(var i = 0, len = myArray.length; i < len; i++) {
    if (myArray[i].hello === searchTerm) {
        index = i;
        break;
    }
}

또는 기능으로 :

function arrayObjectIndexOf(myArray, searchTerm, property) {
    for(var i = 0, len = myArray.length; i < len; i++) {
        if (myArray[i][property] === searchTerm) return i;
    }
    return -1;
}
arrayObjectIndexOf(arr, "stevie", "hello"); // 1

몇 가지 참고 사항 :

  1. 배열에서 for ... in 루프를 사용하지 마십시오
  2. "바늘"을 찾은 후에는 루프에서 벗어나거나 기능에서 복귀하십시오.
  3. 객체 평등에주의

예를 들어

var a = {obj: 0};
var b = [a];
b.indexOf({obj: 0}); // -1 not found

이 함수는 searchTerm이어야하기 때문에 검색어 비교가 잘못되었습니다 :)
Antonio Laguna

여러 번 발생했습니다
Joe

3
@SteveBennett 성능 최적화 버전입니다. 배열의 길이는 한 번만 결정해야합니다 (for-loop의 변수가 초기화 될 때). 귀하의 경우, 길이는 새로 반복 될 때마다 확인됩니다. stackoverflow.com/questions/5349425/…stackoverflow.com/questions/8452317/… 도 참조하십시오. 그러나 성능이 높지 않으면 실제로 중요하지 않습니다.
loother

1
좋은 답변이지만 성능 벤치마킹 ( jsperf.com/find-index-of-object-in-array-by-contents 참조 )을 수행했으며 여기에 언급 된 함수 기반 답변이 두 번째로 가장 높은 답변 인 것으로 나타났습니다. 내 대답 에서 언급했듯이 더 성능이 좋은 유일한 것은 함수 대신 프로토 타입에 넣는 것 입니다.
Uniphonic

123

ES2015에서 이것은 매우 쉽습니다.

myArray.map(x => x.hello).indexOf('stevie')

또는 더 큰 어레이의 성능이 더 좋을 수도 있습니다.

myArray.findIndex(x => x.hello === 'stevie')

2
ES6를 사용하는 좋은 접근 방법
kag

내 대답에서 언급했듯이 이러한 방법 중 어느 것도 프로토 타입 for 루프만큼 성능이 우수하지 않다는 것에 놀랐습니다. findIndex 메소드 브라우저 지원이 약간 열악하지만 동일한 작업을 수행하는 것처럼 보이지만 여전히 성능이 떨어집니다. 벤치 마크에 대한 내 답변의 링크를 참조하십시오.
Uniphonic

현재 수행중인 작업에 성능이 중요한지 알아야합니다. 내 경험으로는 거의 없지만 ymmv입니다.
Steve Bennett

24
var idx = myArray.reduce( function( cur, val, index ){

    if( val.hello === "stevie" && cur === -1 ) {
        return index;
    }
    return cur;

}, -1 );

17

Pablo의 답변이 마음에 들지만 Array # indexOf 및 Array # map이 모든 브라우저에서 작동하지는 않습니다. Underscore는 사용 가능한 경우 기본 코드를 사용하지만 대체 기능도 있습니다. 또한 Pablo의 익명 맵 방법이하는 일을 정확하게 수행하기위한 퍽 방법이 있습니다.

var idx = _.chain(myArray).pluck("hello").indexOf("Stevie").value();

1
Array.prototype.map ()는 IE9 +에 대한 soported되고 당신은 IE8, 7, 6에 대한 Polyfill를 사용할 수 있습니다 developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/...
요한 Echavarria

1
polyfill을 사용할 수 있습니다. . . 또는 밑줄이나 lodash를 사용할 수 있습니다. 기본적으로 다른 많은 것들이 붙어있는 polyfill입니다 . 밑줄에 대한 이의는 무엇입니까? 크기?
tandrewnichols

나는 Underscore를 정말 좋아합니다. 당신의 대답은 영리하지만 IMHO Pablo의 대답은 가장 깨끗합니다.
Johann Echavarria

와우 나는 그런 체인을 사용하지 않았다. 나는 그것이 검색을 유창하게 만드는 방법을 정말로 좋아한다.
Dylan Pierce

chain여기서 불필요한 것입니다. _.pluck(myArray, 'hello').indexOf('stevie')
Steve Bennett

14

또는 프로토 타입을 작성하십시오.

Array.prototype.indexOfObject = function arrayObjectIndexOf(property, value) {
    for (var i = 0, len = this.length; i < len; i++) {
        if (this[i][property] === value) return i;
    }
    return -1;
}

myArr.indexOfObject("name", "stevie");

9
매우 편리합니다! exisitng Array.indexOf 메서드를 방해하지 않도록 prototype.indexOfObject를 선택하지만. Array.prototype.indexOfObject = function(property, value) { for (var i = 0, len = this.length; i < len; i++) { if (this[i][property] === value) return i; } return -1; };
Adam

1
나는 이전 함수가 미리 저장되어있는 자체 실행 클로저로 래핑하고 대체 함수의 첫 번째 라인은의 라인을 따라 무언가를 감쌀 것입니다 if (typeof property === 'string' || typeof property === 'number' || typeof property === 'boolean') return oldIndexOf(property, value);. 이것은 불변의 몇 가지 유형이기 때문입니다. 또한 필요한 경우 기본 메소드로 대체 할 수 있도록 세 번째 인수를 사용합니다.
Isiah Meadows

8

간결한

myArray.indexOf('stevie','hello')

사용 사례 :

  /*****NORMAL****/  
[2,4,5].indexOf(4) ;//OUTPUT 1
 /****COMPLEX*****/
 [{slm:2},{slm:4},{slm:5}].indexOf(4,'slm');//OUTPUT 1
 //OR
 [{slm:2},{slm:4},{slm:5}].indexOf(4,function(e,i){
   return e.slm;
});//OUTPUT 1
/***MORE Complex**/
[{slm:{salat:2}},{slm:{salat:4}},{slm:{salat:5}}].indexOf(4,function(e,i){
   return e.slm.salat;
});//OUTPUT 1

API :

    Array.prototype.indexOfOld=Array.prototype.indexOf

    Array.prototype.indexOf=function(e,fn){
      if(!fn){return this.indexOfOld(e)}
      else{ 
       if(typeof fn ==='string'){var att=fn;fn=function(e){return e[att];}}
        return this.map(fn).indexOfOld(e);
      }
    };

6

여기에서 다양한 답변에 대한 성능 테스트를 수행하여 누구나 스스로 실행할 수 있습니다.

https://jsperf.com/find-index-of-object-in-array-by-contents

Chrome에서 처음 테스트 한 결과, 프로토 타입 내부에서 for 루프 설정을 사용하는 다음 방법이 가장 빠릅니다.

Array.prototype.indexOfObject = function (property, value) {
    for (var i = 0, len = this.length; i < len; i++) {
        if (this[i][property] === value) return i;
    }
    return -1;
}

myArray.indexOfObject("hello", "stevie");

이 코드는 Nathan Zaetta의 답변을 약간 수정 한 것입니다.

성능 벤치 마크에서 대상은 1000 객체 배열의 중간 (인덱스 500)과 끝 (인덱스 999)에 있고 대상을 배열의 마지막 항목으로 넣더라도 (시도) 그것이 발견되기 전에 배열의 모든 단일 항목을 반복해야 함) 여전히 여전히 가장 빠릅니다.

이 솔루션은 또한 마지막 행만 반복하면되기 때문에 반복적으로 실행하기에 가장 간결한 장점 중 하나입니다.

myArray.indexOfObject("hello", "stevie");

2
나는 내 자신의 테스트와 함께 바이올린을 사용 하여이 질문에 대한 답변을 게시하려고했지만 답변 덕분에 더 이상 할 필요가 없습니다. 나는이 같은 결과에 도착하지만, 사용 - 난 그냥 테스트를 확인하려는 while대신 루프를 for하나하고 performance.now(). 나는이 응답을 더 upvoted 것을 원하는 것 그리고 내가 전에 그것을보고 있음을,이 ... 나에게 시간을 저장 한 것
음 Cognyto


5

여기에있는 대부분의 다른 답변은 유효합니다. 때로는 사용하는 곳 근처에서 짧고 간단한 기능을 만드는 것이 가장 좋습니다.

// indexOf wrapper for the list of objects
function indexOfbyKey(obj_list, key, value) {
    for (index in obj_list) {
        if (obj_list[index][key] === value) return index;
    }
    return -1;
}
// Find the string in the list (default -1)
var test1 = indexOfbyKey(object_list, 'name', 'Stevie');
var test2 = indexOfbyKey(object_list, 'last_name', 'some other name');

그것은 당신에게 중요한 것에 달려 있습니다. 코드 줄을 절약하고 하나의 라이너를 사용하거나 다양한 경우를 포괄하는 일반적인 솔루션을 사용하는 것이 매우 영리 할 수 ​​있습니다. 그러나 미래의 개발자들에게 추가적인 리버스 엔지니어링 작업을하는 것보다는 "여기서 이렇게 했어요"라고 말하는 것이 더 낫습니다. 특히 당신이 당신의 질문에서와 같이 자신을 "초보자"라고 생각한다면.


4
array.filter(function(item, indx, arr){ return(item.hello === 'stevie'); })[0];

마음 [0].

의 답변 reduce과 같이 사용 하는 것이 좋습니다 Antonio Laguna.

간결한 사과 ...


4

객체가 배열 내에서 사용하는 객체와 동일한 객체 인 경우 마치 문자열과 동일한 방식으로 객체의 인덱스를 얻을 수 있어야합니다.

var hello = {
    hello: 'world',
    foo: 'bar'
};
var qaz = {
    hello: 'stevie',
    foo: 'baz'
}

var qazCLONE = { // new object instance and same structure
    hello: 'stevie',
    foo: 'baz'
}

var myArray = [hello,qaz];

myArray.indexOf(qaz) // should return 1
myArray.indexOf(qazCLONE) // should return -1

이것은 IndexOf가 값과 일치하는지 또는 무엇인지 불확실했기 때문에 찾고있는 대답입니다. 이제 IndexOf를 사용하여 객체를 찾을 수 있으며 동일한 속성을 가진 다른 객체가 있는지 걱정할 필요가 없습니다.
MDave



3

위치를 찾는 데 관심이 있다면 @ Pablo 's answer을 참조하십시오 .

pos = myArray.map(function(e) { return e.hello; }).indexOf('stevie');

그러나 요소찾는 것을 기대하는 경우 (예 : 이와 같은 작업을 생각하는 myArray[pos]경우)을 사용하여 보다 효율적인 한 줄 방법이 있습니다 filter.

element = myArray.filter((e) => e.hello === 'stevie')[0];

성능 결과보기 (~ + 42 % ops / sec) : http://jsbench.github.io/#7fa01f89a5dc5cc3bee79abfde80cdb3


2

이 예를 참조하십시오 : http://jsfiddle.net/89C54/

for (i = 0; i < myArray.length; i++) {
    if (myArray[i].hello === 'stevie') {
        alert('position: ' + i);
        return;
    }
}

0으로 세기 시작합니다.


2

아래 코드를 확인하고 모든 객체에 작동하는 일반 기능을 만들었습니다.

function indexOfExt(list, item) {
    var len = list.length;

    for (var i = 0; i < len; i++) {
        var keys = Object.keys(list[i]);
        var flg = true;
        for (var j = 0; j < keys.length; j++) {
            var value = list[i][keys[j]];
            if (item[keys[j]] !== value) {
                flg = false;
            }
        }
        if (flg == true) {
            return i;
        }
    }
    return -1;
}

var items = [{ "hello": 'world', "foo": 'bar' }];
var selectedItem = { "hello": 'world', "foo": 'bar' };
alert(items.indexOf(selectedItem));
alert(indexOfExt(items, selectedItem));

첫 번째 경고는 -1 (평균 일치를 찾을 수 없음)을 반환하고 두 번째 경고는 0 (평균 일치를 찾았습니다)을 반환합니다.


2

underscore.js 라이브러리_.findIndex 에서 사용

여기 예가 있습니다 _.findIndex([{a:1},{a: 2,c:10},{a: 3}], {a:2,c:10}) //1


추가 라이브러리에서 메소드를 제안하는 경우 메소드의 출처를 언급해야합니다.
Craicerjack

@Steve Bennett 라이브러리의 멋진 사용. 이제 lodash에 있음
zabusa

2

lodash 또는 다른 라이브러리없이 ES6 findIndex메소드를 사용하여 다음을 작성할 수 있습니다.

function deepIndexOf(arr, obj) {
  return arr.findIndex(function (cur) {
    return Object.keys(obj).every(function (key) {
      return obj[key] === cur[key];
    });
  });
}

이것은 객체의 즉각적인 속성을 비교하지만 속성으로 재귀하지는 않습니다.

구현에서 findIndex아직 제공하지 않는 경우 (대부분은 제공 하지 않음)이 검색을 지원하는 라이트 폴리 필을 추가 ​​할 수 있습니다.

function deepIndexOf(arr, obj) {
  function findIndex = Array.prototype.findIndex || function (pred) {
    for (let i = 0; i < this.length; ++i) {
      if (pred.call(this, this[i], i)) {
        return i;
      }
    }

    return -1;
  }

  return findIndex.call(arr, function (cur) {
    return Object.keys(obj).every(function (key) {
      return obj[key] === cur[key];
    });
  });
}

( 이 속임수에 대한 나의 대답에서 )


2

기본적이고 편리한 기능을 Array.prototype.findIndex()기본적으로 사용할 수 있습니다 .

findIndex () 메소드는 배열의 요소가 제공된 테스트 기능을 만족하는 경우 배열의 색인을 리턴합니다. 그렇지 않으면 -1이 반환됩니다.

Internet Explorer, Opera 및 Safari에서는 지원되지 않지만 아래 링크에 제공된 Polyfill을 사용할 수 있습니다.

추가 정보:

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

var hello = {
  hello: 'world',
  foo: 'bar'
};
var qaz = {
  hello: 'stevie',
  foo: 'baz'
}

var myArray = [];
myArray.push(hello, qaz);

var index = myArray.findIndex(function(element, index, array) {
  if (element.hello === 'stevie') {
    return true;
  }
});
alert('stevie is at index: ' + index);


2

의 Furthor @Monika Garg를 응답 , 당신은 사용할 수 있습니다 findIndex()(A가 polyfill unsupprted 브라우저가).

나는 사람들 이이 대답을 내리는 것을 보았고 나는 그들이 잘못된 구문 때문에이 작업을 수행하기를 희망합니다. 내 의견으로는 이것이 가장 우아한 방법이기 때문입니다.

findIndex () 메소드는 배열의 요소가 제공된 테스트 기능을 만족하는 경우 배열의 색인을 리턴합니다. 그렇지 않으면 -1이 반환됩니다.

예를 들면 다음과 같습니다.

var hello = {
  hello: 'world',
  foo: 'bar'
};
var qaz = {
  hello: 'stevie',
  foo: 'baz'
}

var myArray = [];
myArray.push(hello,qaz);

var index = myArray.findIndex(function(element) {
  return element.hello == 'stevie';
});

alert(index);


이 방법은 우아해 보이지만 MDN에 따르면 IE를 지원하지 않습니까? developer.mozilla.org/en/docs/Web/JavaScript/Reference/…
Jaakko Karhu

polyfill을 사용하십시오 (답변의 링크).
Mosh Feu

1

이것이 배열에서 객체의 인덱스를 찾는 방법입니다

    var myArray = [{  hello: 'world',
        foo: 'bar'
    },{
        hello: 'stevie',
        foo: 'baz'
    }];



    for (i = 0; i < myArray.length; i++) {
        if (myArray[i].hello === 'stevie') {
            alert('position: ' + i);
            return;
        }
    }

0

이것은 사용자 정의 코드없이 작동합니다

var arr, a, found;
arr = [{x: 1, y: 2}];
a = {x: 1, y: 2};
found = JSON.stringify(arr).indexOf(JSON.stringify(a)) > - 1;
// found === true

참고 : 이것은 실제 색인을 제공하지 않으며 객체가 현재 데이터 구조에 존재하는지 알려줍니다.


1
이것은 인덱스를 얻을 수 없기 때문에 유효하지 않습니다
Antonio Laguna

0

간단하게 사용할 수 있습니다

const someId = 2;
const array = [{id:1}, {id:2}, {id:3}];
const index = array.reduce((i, item, index) => item.id === someId ? index : i, -1);
alert('someId ' + someId + ' is at index ' + index);

밑줄도없고 줄임말입니다.


0
var hello = {hello: "world",  foo: "bar"};
var qaz = {hello: "stevie", foo: "baz"};
var myArray = [];
myArray.push(hello,qaz);

function indexOfObject( arr, key, value   ) {
    var j = -1;
    var result = arr.some(function(obj, i) { 
        j++;
        return obj[key] == value;
    })

    if (!result) {
        return -1;
    } else {
        return j;
    };
}

alert(indexOfObject(myArray,"hello","world"));

Array some method를 사용하십시오.
user3235365


-2

findIndex()방법 을 사용하는 것을 선호합니다 .

 var index = myArray.findIndex('hello','stevie');

index 색인 번호를 알려줍니다.


1
답변, 맞춤법 및 코드 들여 쓰기 및 :)가 잘못 되었습니까?
Sachin Verma

1
findIndex는 자바 스크립트 표준 구현에 없습니다. 그러한 방법에 대한 다가오는 (ecma 6) 제안이 있지만 서명은 그렇지 않습니다. 의미를 명확히하고 (메소드 이름 일 수도 있음) findIndex 메소드 선언을 지정하거나 사용중인 라이브러리 이름을 지정하십시오.
Sebastien F.
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.