Nesnenin dizinini JavaScript'te özelliğine göre nasıl alabilirim?


241

Örneğin, ben var:

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

Sonra bu nesneyi sıralamak / tersine çevirmek istiyorumname örneğin . Ve sonra böyle bir şey almak istiyorum:

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

Ve şimdi özelliği olan nesnenin dizinini bilmek istiyorum name='John' özellik belirtecinin değerini almak için .

Sorunu nasıl çözebilirim?


Mülkü aramadan önce listeyi neden sıralamak istiyorsunuz?
JJJ

JavaScript nesneleri, {Key:Value}sizin için düzelttim.
Rocket Hazmat


Cevapları tararsanız, bazı yerel Datanesneler var gibi görünür . Bu sadece sözleşmeye aykırı olan büyük harfle yazılmış bir değişken adıdır. Başka biri bundan rahatsız olursa, bu adlandırmada sorunu ve cevapları düzenleyeceğim.
Roy Prins

Yanıtlar:


170

Diğer cevapların önerdiği gibi, dizi boyunca döngü muhtemelen en iyi yoldur. Ama onu kendi işlevine koyardım ve biraz daha soyut hale getirirdim:

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

Bununla, sadece hangisinin 'John' içerdiğini bulmakla kalmaz, aynı zamanda '312312' jetonunu da bulabilirsiniz:

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

DÜZENLEME: Array.prototype.indexOf () ile aynı yapıyı izleyecek şekilde bulunamadığında -1 döndürme işlevi güncellendi


1
Birden fazla öznitelik seviyesinden daha derin arama yapmayı kapsayacak şekilde genişleten cevap eklendi. Bunun için teşekkürler Chris - gerçekten yardım etti: D
Ed Shee

3
Bu çözümle ilgili sorun yaşayacaklar için, === eşittir işaretinin sadece değeri değil veri türünü de kontrol edeceğini unutmayın. gerçek değer bir dize ise tarih, sayılar ve boş değerlerin karşılaştırılması false değerini döndürebilir. Veri türü sizin için önemli değilse == eşittir işaretini kullanabilirsiniz.
David Addoteye

BUNU YAPMAYIN. Üst düzey işlevleri nasıl kullanacağınızı öğrenin, bu eski şeyleri yapmanın eski yoludur.
Led

327

Sıralama bölümü zaten yanıtlandığından. Dizinizdeki bir mülkün indexOf'unu almanın başka zarif bir yolunu önereceğim

Örneğin:

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

Yapabilirsin:

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

Array.prototype.mapIE7 veya IE8'de mevcut değildir. ES5 Uyumluluğu

Ve işte ES6 ve ok sözdizimi ile, daha da basit:

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

4
Ne olursa olsun tüm dizi yinelemek zorunda. İlk yönteme gerek yoktur.
Alman Attanasio

1
Basit, ancak büyük veri kümeleri kullanırken performansı dikkate alın
gavioto

1
Gerçekten harika bir cevap bu sorunla bana yardımcı oldu!
NiallMitch14

1
Bu çözüm çok güzel. Bin yaşında yaşasın, efendim.
deepelement

3
ES6 sürümünde bir harita ve ardından indexOf yapmak, dizinin üzerinde iki kez döngü yapacakları anlamına gelir. Bunun yerine cevabımda gösterilen findIndex yöntemini kullanmalısınız
silverlight513

209

ES6 kullanma konusunda sorun yaşıyorsanız. Diziler artık findIndex işlevine sahip. Yani böyle bir şey yapabilirsiniz:

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

6
eller aşağı en doğrudan ve zarif çözüm, ben küçük bir yapmak istiyorum findIndex açgözlü - benim durumumda mükemmel - ama kullanıcılar yinelenen değerlere sahip nesneler varsa (yani iki nesne ile name: John) bu sadece döneceğini unutmayın ilk maç
GrayedFox

Korku veren !! Teşekkür ederim.
moreirapontocom

@GrayedFox açgözlü DEĞİL demek istemediniz mi? Açgözlü daha fazla sonuç anlamına gelir ve findIndex sadece ilk eşleşmeyi döndürür.
Jos

1
Maalesef @Jos ama açgözlü bir arama algoritmasının ne yaptığını tam olarak anlamadığınızı düşünüyorum . Açgözlü bir algoritma, yalnızca eldeki bilgileri dikkate alır; bu, yalnızca bir sonuca ihtiyacınız olduğunda listede bir öğeyi aramak için hesaplama açısından etkilidir. FindIndex yöntemi, yalnızca ilk eşleşmeyi döndürdüğü için açgözlü bir yöntemdir. Açgözlü olmasaydı aramaya devam ederdi. Günlük İngilizce'de kullanıldığı gibi "açgözlü" terimini düşünüyorsunuz, ancak programlama bağlamında (yani SO), düşündüğünüzün tam tersi;)
GrayedFox

@GrayedFox'u açıkladığınız için teşekkür ederiz. Açgözlüğe referansım aslında programlamadan da oldu, ancak açgözlü olmayanların açgözlü olmayandan daha fazla karakter aldığı normal ifadelerle ilgiliydi! :-)
Jos

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

Hangi basitleştirilmiş bir versiyonu:

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

Gönderen mozilla.org:

FindIndex () yöntemi, dizideki sağlanan test işlevini karşılayan ilk öğenin dizinini döndürür. Aksi takdirde -1 döndürülür.


2
Bu cevapta eksik olan tek şey dize karşılaştırması için "===" kullanın.
Bruno Tavares

@BrunoTavares, bu durumda hangi senaryonun farklı olacağını düşünüyorsunuz?
edank

1
@edank Eğer OP kontrol etmek vardı tokenyerine alanını nameolarak, bu alanda sorunlar olabilir Data[0].token == 312312için değerlendirir true, ancak Data[0].token === 321321hiç değerlendirir false.
kem

@edank bu cevaba bir göz atın stackoverflow.com/questions/359494/…
Bruno Tavares

23

IE ile ilgili sorun yaşıyorsanız, 9.0'dan itibaren desteklenen map () işlevini kullanabilirsiniz:

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

1
Aşağıdaki cevap daha fazla bilgi sağlar ve önce gönderilir.
Alexander

Bu kesinlikle bunun için en iyi çözümdür.
Bebolicious

4

Benim için bilinen tek yol, tüm dizi arasında döngü yapmaktır:

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

veya büyük / küçük harfe duyarlı değil:

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

Sonuçta değişken dizini nesnenin dizinini veya bulunamazsa -1'i içerir.


2

prototip bir yol

(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.

Durumumda çalışmak için bunu biraz değiştirmek zorunda kaldım - null değeri olan bir mülkün dizinini arıyordum ve beşinci satır bunun bu indeksi atlamasına neden oluyordu.
David Brunow

1

Sıralama sisteminizi tanımlamak için parametre olarak özel bir işlev kullanarak Array.sort'u kullanabilirsiniz.

Örneğinizde, aşağıdakileri verir:

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'

Sıralama işlevi a'nın b'den önce gelmesi durumunda -1, her ikisinin de eşit olması durumunda a'nın b'den sonra gelmesi ve her ikisinin eşit olması durumunda 0 değerini döndürmesi gerekir. Diziyi sıralamak için sıralama işlevinizde doğru mantığı tanımlamak size kalmıştır.

Düzenleme: Sorunuzun dizini bilmek istediğiniz son bölümünü kaçırdınız. Diğerlerinin söylediği gibi bulmak için dizi üzerinden döngü gerekir.


1

Dizinizi gözden geçirin ve konumu bulun:

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

Bu if(Data[item].name == 'John')senin için düzelttim.
Rocket Hazmat

Bunun bir anı var. 'Bulunamadı' değişkeni i pozitif indeks içerir. Ve 'bulunamadı' test etmek i === Data.length
Andrew D.

İkincisi, dizinin indexer olmayan özel özellikler içermesidir. Örneğin: var Veri [1,2,3,4,5]; Veri [ "test"] 7897 =; Çıktısını karşılaştırın: for (Data'da var i) uyarısı (Data [i]); ve (var i = 0; i <Data.length; i ++) uyarısı (Data [i]) için;
Andrew D.


1

Neden küçük bir çözüm kullanmıyorsunuz?

Dizin olarak adlarla yeni bir dizi oluşturun. bundan sonra tüm aramalar dizinleri kullanır. Yani, sadece bir döngü. Bundan sonra tüm elemanlar arasında geçiş yapmanız gerekmez!

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

canlı örnek.


Bu, her şeyi önce döngüye almak ... sonra nesneleri değiştirmek anlamına gelir (onları klonlamadığınız sürece, ancak bu daha da fazla yüktür). Bundan sonra tekrar döngü yapıyorsunuz (en azından kısmen).
Jos

1

Chris Pickett'in cevabını uzattım çünkü benim durumumda bir özellik seviyesinden daha derin arama yapmam gerekiyordu:

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' işlevine iletilebilir


1

Peki buna ne dersin ? :

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

Lodash veya underscorejs kullandığınızı varsayarsak.


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

İçinde birden çok nesne içeren bir Nesneniz varsa, Ana nesneye bazı nesnelerin dahil edilip edilmediğini bilmek istiyorsanız, find (MasterObject, 'Aranacak Nesne') koyun, bu işlev varsa ya da değilse yanıtı döndürür (DOĞRU veya YANLIŞ) ), Umarım bu konuda yardım, JSFiddle'da örnek görebilirsiniz .


Bu cevabın mevcut sorunu düzeltmede
OP'ye

@ ρяσѕρєяK, Öneriniz için teşekkürler, zaten açıklamayı ekliyorum :)
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

Bu kod snippet'i soruyu çözebilir, ancak bir açıklama da dahil olmak üzere , yayınınızın kalitesini artırmaya yardımcı olur. Gelecekte okuyucular için soruyu cevapladığınızı ve bu kişilerin kod önerinizin nedenlerini bilmeyebileceğini unutmayın. Lütfen hem kodun hem de açıklamaların okunabilirliğini azalttığı için kodunuzu açıklayıcı yorumlarla doldurmamaya çalışın!
Hoşçakal StackExchange

1

Özellik belirtecinin değerini almak istiyorsanız, bunu da deneyebilirsiniz

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

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

burada _.findKey bir lodash'ın işlevi


0

Alman Attanasio Ruiz'in cevabına alternatif olarak, Array.map () yerine Array.reduce () kullanarak 2. döngüyü ortadan kaldırabilirsiniz;

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

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.