วิธีรับดัชนีวัตถุโดยคุณสมบัติใน 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}ฉันแก้ไขให้คุณ
Rocket Hazmat


หากคุณสแกนคำตอบดูเหมือนว่ามีDataวัตถุดั้งเดิมอยู่ มันเป็นเพียงชื่อตัวแปรตัวพิมพ์ใหญ่ซึ่งขัดกับการประชุม หากใครก็ตามที่ใส่ใจสิ่งนี้ฉันจะแก้ไขคำถามและคำตอบเพื่อแก้ไขการตั้งชื่อนี้
Roy Prins

คำถามที่เกี่ยวข้อง: stackoverflow.com/questions/10557486/…
Anton Tarasenko

คำตอบ:


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

ด้วยสิ่งนี้ไม่เพียง แต่คุณจะพบว่าอันไหนมี 'จอห์น' แต่คุณสามารถค้นหาที่มีโทเค็น '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
Ed Shee

3
สำหรับผู้ที่จะมีปัญหากับการแก้ปัญหานี้โปรดจำไว้ว่าเครื่องหมาย = = เท่ากับจะไม่เพียงตรวจสอบค่า แต่ยังประเภทข้อมูล ดังนั้นการเปรียบเทียบวันที่ตัวเลขและค่าว่างอาจส่งคืนค่าเท็จหากค่าจริงเป็นสตริง คุณสามารถใช้ == เครื่องหมายเท่ากับหากประเภทข้อมูลนั้นไม่มีสาระสำคัญสำหรับคุณ
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.mapไม่พร้อมใช้งานบน IE7 หรือ IE8 ความเข้ากันได้ของ ES5

และที่นี่มี ES6 และลูกศรไวยากรณ์ซึ่งง่ายกว่า:

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

4
ฉันต้องย้ำอาร์เรย์ทั้งหมดไม่ว่าจะเกิดอะไรขึ้น วิธีแรกไม่จำเป็นต้อง
เยอรมัน Attanasio

1
เรียบง่าย แต่คำนึงถึงประสิทธิภาพเมื่อใช้ชุดข้อมูลขนาดใหญ่
gavioto

1
คำตอบที่ดีจริงๆช่วยฉันด้วยปัญหานี้!
NiallMitch14

1
วิธีนี้น่ารัก ขอให้คุณมีชีวิตอยู่ได้หนึ่งพันปีครับ
deepelement

3
การทำแผนที่และ indexOf ในเวอร์ชั่น ES6 นั้นหมายความว่าพวกมันจะวนซ้ำอาร์เรย์เป็นสองเท่า คุณควรใช้วิธี findIndex ที่แสดงในคำตอบของฉัน
silverlight513

209

ถ้าคุณสบายดีเมื่อใช้ ES6 ตอนนี้อาร์เรย์มีฟังก์ชันfindIndex ซึ่งหมายความว่าคุณสามารถทำสิ่งนี้:

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

6
ส่งมอบโซลูชันที่ตรงที่สุดและสง่างามฉันจะทำให้เล็กไม่ findIndex เป็นโลภ - ในกรณีของฉันที่สมบูรณ์แบบ - แต่ผู้ใช้จะต้องระวังว่าถ้าคุณมีวัตถุที่มีค่าซ้ำกัน (เช่นวัตถุสองกับname: John) นี้จะกลับมาเท่านั้น นัดแรก
GrayedFox

น่ากลัว !! ขอบคุณ.
moreirapontocom

@GrayedFox คุณไม่ได้หมายความว่าไม่โลภ? โลภหมายถึงผลลัพธ์ที่มากขึ้นและ 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
ใช้ "===" สำหรับการเปรียบเทียบสตริงเป็นสิ่งเดียวที่ขาดหายไปในคำตอบนี้
บรูโน่ทาวาเรส

@BrunoTavares คุณคิดว่าสถานการณ์แบบใดที่แตกต่างในกรณีนี้
edank

1
@edank หาก OP มีการตรวจสอบtokenข้อมูลแทนการใช้nameข้อมูลอาจจะมีปัญหาตามที่Data[0].token == 312312ประเมินtrueแต่ประเมินData[0].token === 321321 false
kem

@edank ดูในคำตอบนี้stackoverflow.com/questions/359494/…
Bruno Tavares

23

หากคุณมีปัญหากับ IE คุณสามารถใช้ฟังก์ชั่น map () ซึ่งรองรับตั้งแต่ 9.0 เป็นต้นไป:

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.

ฉันต้องเปลี่ยนสิ่งนี้เล็กน้อยเพื่อให้เหมาะกับสถานการณ์ของฉัน - ฉันกำลังมองหาดัชนีของทรัพย์สินที่มีค่าเป็นโมฆะและบรรทัดที่ห้าทำให้สิ่งนี้ข้ามไปที่ดัชนีนั้น
David Brunow

1

คุณสามารถใช้ Array.sort โดยใช้ฟังก์ชั่นที่กำหนดเองเป็นพารามิเตอร์ในการกำหนด mecanism ของคุณ

ในตัวอย่างของคุณมันจะให้:

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'

ฟังก์ชัน sort ต้องส่งคืน -1 ถ้า a ควรมาก่อน b, 1 ถ้า a ควรมาหลัง b และ 0 หากทั้งสองเท่ากัน มันขึ้นอยู่กับคุณในการกำหนดตรรกะที่ถูกต้องในฟังก์ชั่นการเรียงลำดับของคุณเพื่อจัดเรียงอาร์เรย์

แก้ไข: พลาดคำถามสุดท้ายที่คุณต้องการรู้ดัชนี คุณจะต้องวนซ้ำอาร์เรย์เพื่อหาสิ่งที่คนอื่นพูด


1

เพียงผ่านอาร์เรย์ของคุณและค้นหาตำแหน่ง:

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

if(Data[item].name == 'John')ฉันควรจะแก้ไขให้คุณ
Rocket Hazmat

มีอยู่ช่วงเวลาหนึ่ง หากตัวแปร 'ไม่พบ' ฉันมีดัชนีเป็นบวก และเพื่อทดสอบ 'ไม่พบ' ต้องเปรียบเทียบถ้า i === Data.length
Andrew D.

วินาทีที่สองคือถ้าอาร์เรย์มีคุณสมบัติแบบกำหนดเองที่ไม่ใช่ดัชนี ตัวอย่างเช่น: var Data [1,2,3,4,5]; ข้อมูล [ทดสอบ ""] = 7897; เปรียบเทียบเอาต์พุตของ: สำหรับการแจ้งเตือน (var i ในข้อมูล) (Data [i]); และสำหรับ (var i = 0; i <Data.length; i ++) การแจ้งเตือน (Data [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') ฟังก์ชั่นนี้จะส่งกลับการตอบสนองหากมีอยู่จริงหรือไม่ ) ผมหวังว่าความช่วยเหลือเกี่ยวกับเรื่องนี้สามารถดูกันตัวอย่างใน JSFiddle


เพิ่มคำอธิบายพร้อมคำตอบสำหรับวิธีที่คำตอบนี้ช่วย OP ในการแก้ไขปัญหาปัจจุบัน
Kяσѕρєя K

@ ρяσѕρєяKขอบคุณสำหรับข้อเสนอแนะของคุณฉันแล้วเพิ่มคำอธิบาย :)
เปโดรมอนเต 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

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

อีกทางเลือกหนึ่งสำหรับคำตอบของเยอรมัน Attanasio Ruiz คุณสามารถกำจัดลูปที่ 2 โดยใช้ Array.reduce () แทน Array.map ();

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.