JavaScript에서 속성별로 객체 색인을 얻는 방법은 무엇입니까?


241

예를 들어, 나는 :

var Data = [
  { id_list: 1, name: 'Nick', token: '312312' },
  { id_list: 2, name: 'John', token: '123123' },
]

그런 다음 예를 들어이 객체 를 정렬 / 역전 하고 싶습니다 name. 그리고 다음과 같은 것을 얻고 싶습니다 :

var Data = [
  { id_list: 2, name: 'John', token: '123123' },
  { id_list: 1, name: 'Nick', token: '312312' },
]

그리고 name='John'속성 토큰의 값을 얻기 위해 속성이있는 객체의 색인을 알고 싶습니다 .

문제를 어떻게 해결합니까?


속성을 검색하기 전에 먼저 목록을 정렬 하시겠습니까?
JJJ

JavaScript 객체는 {Key:Value}입니다.
로켓 Hazmat


답변을 스캔하면 기본 Data객체 가있는 것처럼 나타납니다 . 단지 대문자로 된 변수 이름이며 이는 규칙에 위배됩니다. 다른 사람이 이것으로 방해한다면, 나는이 이름을 고치기 위해 질문과 대답을 편집 할 것입니다.
Roy Prins 2014 년

답변:


170

다른 답변에서 알 수 있듯이 배열을 반복하는 것이 가장 좋은 방법 일 것입니다. 그러나 나는 그것을 자체 기능에 넣고 조금 더 추상적으로 만들 것입니다.

function findWithAttr(array, attr, value) {
    for(var i = 0; i < array.length; i += 1) {
        if(array[i][attr] === value) {
            return i;
        }
    }
    return -1;
}

var Data = [
    {id_list: 2, name: 'John', token: '123123'},
    {id_list: 1, name: 'Nick', token: '312312'}
];

이를 통해 'John'이 포함 된 것을 찾을 수있을뿐만 아니라 '312312'토큰이 포함 된 것을 찾을 수 있습니다.

findWithAttr(Data, 'name', 'John'); // returns 0
findWithAttr(Data, 'token', '312312'); // returns 1
findWithAttr(Data, 'id_list', '10'); // returns -1

편집 : 찾을 수 없을 때 -1을 반환하도록 함수가 업데이트되었으므로 Array.prototype.indexOf () 와 동일한 구문을 따릅니다.


1
하나의 속성 수준보다 더 깊이있는 검색을 포괄하도록 확장 된 답변을 추가했습니다. 이 크리스 감사합니다-정말 도움이 : D
에드시

3
이 솔루션에 문제가있는 사람들에게 === 등호는 값뿐만 아니라 데이터 유형도 검사한다는 점을 기억하십시오. 따라서 실제 값이 문자열 인 경우 날짜, 숫자 및 빈 값을 비교하면 false가 반환 될 수 있습니다. 데이터 유형이 본질적이지 않은 경우 == 등호를 사용할 수 있습니다.
David Addoteye

이러지 마십시오. 고기능 함수를 사용하는 방법을 배우십시오.
주도

327

정렬 부분이 이미 답변되었으므로. 배열에서 속성의 indexOf를 얻는 또 다른 우아한 방법을 제안하려고합니다.

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

var Data = [
    {id_list:1, name:'Nick',token:'312312'},
    {id_list:2,name:'John',token:'123123'}
]

넌 할 수있어:

var index = Data.map(function(e) { return e.name; }).indexOf('Nick');

Array.prototype.mapIE7 또는 IE8에서는 사용할 수 없습니다. ES5 호환성

그리고 여기 ES6와 화살표 구문이 있습니다.

const index = Data.map(e => e.name).indexOf('Nick');

4
무엇이든 상관없이 전체 배열을 반복해야합니다. 첫 번째 방법은 필요하지 않습니다.
독일 Attanasio

1
단순하지만 큰 데이터 세트를 사용할 때의 성능을 고려하십시오
gavioto

1
정말 큰 대답이이 문제에 도움이되었습니다!
NiallMitch14

1
이 솔루션은 사랑 스럽습니다. 천 살이 되시길 바랍니다.
deepelement

3
ES6 버전에서 map을하고 indexOf를하는 것은 배열을 두 번 반복한다는 의미입니다. 대신 내 답변에 표시된 findIndex 메서드를 사용해야합니다
silverlight513

209

ES6을 사용해도 괜찮다면. 배열에는 이제 findIndex 함수가 있습니다. 이것은 다음과 같은 것을 할 수 있음을 의미합니다.

const index = Data.findIndex(item => item.name === 'John');

6
가장 직접적이고 우아한 솔루션을 손에 넣으면 findIndex가 욕심이 아닌 작은 것을 만들 것입니다. 제 경우에는 완벽했습니다. 그러나 값이 중복 된 객체가있는 경우 (즉, 두 개의 객체가있는 경우 name: John) 이것이 반환됩니다. 첫 경기
GrayedFox

대박!! 감사합니다.
moreirapontocom

@GrayedFox는 탐욕스럽지 않다는 것을 의미하지 않습니까? Greedy는 더 많은 결과를 의미하며 findIndex는 첫 번째 일치 항목 만 반환합니다.
Jos

1
@Jos 미안하지만 욕심 많은 검색 알고리즘이 무엇을 이해하지 못하는 것 같습니다 . 탐욕스러운 알고리즘은 현재 보유하고있는 정보 만 고려하므로, 결과가 하나만 필요할 때 목록에서 항목을 검색하는 데 계산적으로 효율적입니다. findIndex 메소드는 첫 번째 일치 항목 만 리턴하므로 욕심이 많습니다. 탐욕스럽지 않으면 계속 검색합니다. 일상적인 영어로 사용되는 "욕심쟁이"라는 용어를 생각하고 있지만 프로그래밍의 맥락에서 (예 : SO) 생각과는 반대입니다.)
GrayedFox

@GrayedFox를 설명해 주셔서 감사합니다. 욕심에 대한 나의 언급은 실제로 프로그래밍에서 나온 것이지만 욕심은 욕심이 아닌 것보다 더 많은 문자를 취하는 정규식과 관련이 있습니다! :-)
Jos

28
var index = Data.findIndex(item => item.name == "John")

다음은 단순화 된 버전입니다.

var index = Data.findIndex(function(item){ return item.name == "John"})

에서 mozilla.org :

findIndex () 메소드는 제공된 테스트 함수를 만족하는 배열의 첫 번째 요소 색인을 리턴합니다. 그렇지 않으면 -1이 반환됩니다.


2
문자열 비교에 "==="를 사용하면이 답변에서 유일하게 누락 된 것입니다.
Bruno Tavares 2016 년

@BrunoTavares,이 경우 어떤 시나리오가 다를 것이라고 생각하십니까?
edank

1
@edank OP가 token필드 대신 필드 를 확인하는 경우에 평가할 name때 문제가있을 수 있지만에 평가됩니다 . Data[0].token == 312312trueData[0].token === 321321false
kem

@edank이 답변에서 살펴보십시오 stackoverflow.com/questions/359494/…
Bruno Tavares

23

IE에 문제가있는 경우 9.0 이상에서 지원되는 map () 함수를 사용할 수 있습니다.

var index = Data.map(item => item.name).indexOf("Nick");

1
아래의 답변 은 자세한 정보를 제공하며 처음 게시되었습니다.
Alexander

이것은 확실히 최선의 해결책입니다.
Bebolicious

4

나에게 알려진 유일한 방법은 모든 배열을 반복하는 것입니다.

var index=-1;
for(var i=0;i<Data.length;i++)
  if(Data[i].name==="John"){index=i;break;}

또는 대소 문자를 구분하지 않습니다 :

var index=-1;
for(var i=0;i<Data.length;i++)
  if(Data[i].name.toLowerCase()==="john"){index=i;break;}

결과 변수 인덱스 에 오브젝트의 인덱스가 있거나 찾지 못한 경우 -1이 포함됩니다.


2

프로토 타입 방식

(function(){
  if (!Array.prototype.indexOfPropertyValue){
    Array.prototype.indexOfPropertyValue = function(prop,value){
      for (var index = 0; index < this.length; index++){
        if (this[index][prop]){
          if (this[index][prop] == value){
            return index;
          }
        }
      }
      return -1;
    }
  }
 })();
 // usage:
 var Data = [
 {id_list:1, name:'Nick',token:'312312'},{id_list:2,name:'John',token:'123123'}];
 Data.indexOfPropertyValue('name','John'); // returns 1 (index of array);
 Data.indexOfPropertyValue('name','Invalid name') // returns -1 (no result);
 var indexOfArray = Data.indexOfPropertyValue('name','John');
 Data[indexOfArray] // returns desired object.

상황에 따라 작동하도록 약간 변경해야했습니다. 값이 null 인 속성의 색인을 찾고 있었고 다섯 번째 줄로 인해 해당 색인을 건너 뛰었습니다.
David Brunow

1

사용자 지정 함수를 매개 변수로 사용하여 Array.sort를 사용하여 정렬 메커니즘을 정의 할 수 있습니다.

귀하의 예에서 다음을 제공합니다.

var Data = [
    {id_list:1, name:'Nick',token:'312312'},{id_list:2,name:'John',token:'123123'}
]

Data.sort(function(a, b){
    return a.name < b.name ? -1 : a.name > b.name ? 1 : 0;
});

alert("First name is : " + Data[0].name); // alerts 'John'
alert("Second name is : " + Data[1].name); // alerts 'Nick'

정렬 함수는 a가 b보다 앞에 오면 -1을, a가 b보다 뒤에 오면 1을, 둘 다 같으면 0을 리턴해야합니다. 정렬 기능에서 올바른 논리를 정의하여 배열을 정렬하는 것은 사용자의 책임입니다.

편집 : 색인을 알고 싶은 질문의 마지막 부분을 놓쳤습니다. 다른 사람들이 말했듯이 배열을 반복해야합니다.


1

배열을 살펴보고 위치를 찾으십시오.

var i = 0;
for(var item in Data) {
    if(Data[item].name == 'John')
        break;
    i++;
}
alert(i);

이 문제는 if(Data[item].name == 'John')해결되었습니다.
로켓 Hazmat

이 순간이 있습니다. 변수를 '을 (를) 찾을 수 없습니다'경우 나는 긍정적 인 인덱스가 포함되어 있습니다. '찾을 수 없음'을 테스트하려면 i === Data.length 인 경우 비교해야합니다
.

두 번째 순간은 배열에 인덱서가 아닌 사용자 정의 속성이 포함 된 경우입니다. 예를 들면 다음과 같습니다. var Data [1,2,3,4,5]; 데이터 [ "test"] = 7897; 출력을 비교합니다 : for (var i in Data) alert (Data [i]); 위해 (VAR I = 0; I <data.length입니다 단계; I ++) 경보 (데이터 [I]);
Andrew D.


1

작은 해결 방법을 사용하지 않는 이유는 무엇입니까?

이름을 인덱스로 사용하여 새 배열을 만듭니다. 그 후 모든 검색은 색인을 사용합니다. 따라서 하나의 루프 만 있습니다. 그 후 모든 요소를 ​​반복 할 필요는 없습니다!

var Data = [
    {id_list:1, name:'Nick',token:'312312'},{id_list:2,name:'John',token:'123123'}
    ]
var searchArr = []
Data.forEach(function(one){
  searchArr[one.name]=one;
})
console.log(searchArr['Nick'])

http://jsbin.com/xibala/1/edit

라이브 예.


즉, 모든 것을 먼저 반복하면서 객체를 수정해야합니다 (복제하지 않으면 더 많은 오버 헤드입니다). 그리고 그 후에 당신은 (부분적으로는 적어도) 다시 반복합니다.
Jos

1

Chris Pickett의 답변을 확장했습니다. 제 경우에는 하나의 속성 수준보다 더 깊이 검색해야했습니다.

function findWithAttr(array, attr, value) {
  if (attr.indexOf('.') >= 0) {
    var split = attr.split('.');
    var attr1 = split[0];
    var attr2 = split[1];
    for(var i = 0; i < array.length; i += 1) {
      if(array[i][attr1][attr2] === value) {
        return i;
      }
    }
  } else {
    for(var i = 0; i < array.length; i += 1) {
      if(array[i][attr] === value) {
        return i;
      }
    }
  };
};

'attr1.attr2'를 함수에 전달할 수 있습니다


1

이건 어때? :

Data.indexOf(_.find(Data, function(element) {
  return element.name === 'John';
}));

lodash 또는 밑줄을 사용한다고 가정합니다.


1
var fields = {
teste:
{
    Acess:
    {
        Edit: true,
      View: false

      }
 },
teste1:
{
    Acess:
    {
        Edit: false,
      View: false

      }
  }
};

console.log(find(fields,'teste'));
function find(fields,field){
    for(key in fields){
        if(key == field){
        return true;
    }
}
return false;
}

내부에 곱하기 객체가있는 하나의 객체가있는 경우 일부 객체가 마스터 객체에 포함되어 있는지 확인하려면 find (MasterObject, 'Object to Search')를 넣으십시오.이 함수는 존재하거나 존재하지 않는 경우 (TRUE 또는 FALSE) 응답을 반환합니다 ), 이것에 도움이되기를 바랍니다 .JSFiddle 의 예를 볼 수 있습니다 .


이 답변이 현재 문제를 해결하는 데 OP에 도움이되는 방법에 대한 답변이 포함 된 설명을 추가하십시오
ρяσѕρєя K

@ ρяσѕρєяK, 귀하의 제안에 감사드립니다, 나는 이미 설명을 추가합니다 :)
Pedro Monteiro Arantes

1
let indexOf = -1;
let theProperty = "value"
let searchFor = "something";

theArray.every(function (element, index) {

    if (element[theProperty] === searchFor) {
        indexOf = index;
        return false;
    }
    return true;
});

1
collection.findIndex(item => item.value === 'smth') !== -1

이 코드 스 니펫은 문제를 해결할 수 있지만 설명을 포함하면 게시물의 품질을 향상시키는 데 실제로 도움이됩니다. 앞으로 독자에게 질문에 대한 답변을 제공하고 있으며 해당 사람들이 코드 제안의 이유를 모를 수도 있습니다. 또한 코드와 설명의 가독성을 떨어 뜨리므로 설명 주석으로 코드를 혼동하지 마십시오!
Goodbye StackExchange 2012 년

1

속성 토큰의 가치를 얻고 싶다면 이것을 시도해보십시오

    let data=[
      { id_list: 1, name: 'Nick', token: '312312' },
      { id_list: 2, name: 'John', token: '123123' },
    ]

    let resultingToken =  data[_.findKey(data,['name','John'])].token

여기서 _.findKey는 lodash의 함수입니다.


0

German Attanasio Ruiz의 답변 대신 Array.map () 대신 Array.reduce ()를 사용하여 두 번째 루프를 제거 할 수 있습니다.

var Data = [
    { name: 'hypno7oad' }
]
var indexOfTarget = Data.reduce(function (indexOfTarget, element, currentIndex) {
    return (element.name === 'hypno7oad') ? currentIndex : indexOfTarget;
}, -1);

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