รับดัชนีของวัตถุภายในอาร์เรย์จับคู่เงื่อนไข


322

ฉันมีอาร์เรย์เช่นนี้:

[{prop1:"abc",prop2:"qwe"},{prop1:"bnmb",prop2:"yutu"},{prop1:"zxvz",prop2:"qwrq"},...]

ฉันจะรับดัชนีของวัตถุที่ตรงกับเงื่อนไขโดยไม่วนซ้ำทั้งอาร์เรย์ได้อย่างไร

ยกตัวอย่างเช่นให้ผมต้องการที่จะได้รับดัชนีprop2=="yutu"1

ผมเห็นแต่คิดว่ามันใช้สำหรับอาร์เรย์ง่ายๆเช่น.indexOf() ["a1","a2",...]ฉันตรวจสอบด้วยเช่นกัน$.grep()แต่สิ่งนี้คืนค่าวัตถุไม่ใช่ดัชนี

คำตอบ:


733

ตั้งแต่ปี 2559 คุณควรใช้Array.findIndex(มาตรฐาน ES2015 / ES6) สำหรับสิ่งนี้:

a = [
  {prop1:"abc",prop2:"qwe"},
  {prop1:"bnmb",prop2:"yutu"},
  {prop1:"zxvz",prop2:"qwrq"}];
    
index = a.findIndex(x => x.prop2 ==="yutu");

console.log(index);

รองรับใน Google Chrome, Firefox และ Edge สำหรับ Internet Explorer จะมี polyfill อยู่ในหน้าที่เชื่อมโยง

หมายเหตุประสิทธิภาพ

การเรียกใช้ฟังก์ชันมีราคาแพงดังนั้นด้วยอาร์เรย์ขนาดใหญ่จริง ๆ การวนรอบแบบง่ายจะทำงานได้ดีกว่าfindIndex:

let test = [];

for (let i = 0; i < 1e6; i++)
    test.push({prop: i});


let search = test.length - 1;
let count = 100;

console.time('findIndex/predefined function');
    let fn = obj => obj.prop === search;

    for (let i = 0; i < count; i++)
        test.findIndex(fn);
console.timeEnd('findIndex/predefined function');


console.time('findIndex/dynamic function');
    for (let i = 0; i < count; i++)
        test.findIndex(obj => obj.prop === search);
console.timeEnd('findIndex/dynamic function');


console.time('loop');
    for (let i = 0; i < count; i++) {
        for (let index = 0; index < test.length; index++) {
            if (test[index].prop === search) {
                break;
            }
        }
    }
console.timeEnd('loop');

เช่นเดียวกับการเพิ่มประสิทธิภาพส่วนใหญ่ควรใช้ด้วยความระมัดระวังและเฉพาะเมื่อจำเป็นเท่านั้น


3
ฉันไม่เห็นความต้องการอาร์เรย์ชั่วคราวที่นี่ เพียงใช้ข้อเท็จจริงฟังก์ชัน iterator ปิดบริบทและใช้ตัวแปร นอกจากนี้เวอร์ชันที่ไม่ใช่ jQuery ก็ใช้งานไม่ได้ (สมมติว่าเป็นดัชนี0?) ทั้งการแก้ปัญหาการทำมากขึ้นย้ำกว่าที่จำเป็นซึ่งน้อยกว่าเหมาะถ้าอาร์เรย์ที่มีขนาดใหญ่ (แม้ว่าราคาของมันเป็นมนุษย์ขนาดใหญ่เพื่อจะแจ้งให้ทราบที่ต่ำเว้นแต่การค้นหาจะเกิดขึ้นจำนวนมาก )
TJ Crowder

@ thg435: ยังคงคิดว่ามันเป็นเครื่องจักร Rube Goldberg เล็กน้อยซึ่งคันโยกแบบธรรมดาจะทำกลลวงได้ :-) แต่เฮ้มันใช้งานได้!
TJ Crowder

4
คุณช่วยอธิบายวิธีการx => x.prop2=="yutu"ทำงานกับ findIndex () ได้อย่างไร
Abhay Pai

5
@AbhayPai: มันเหมือนกับfunction(x) { return x.prop2=="yutu" }
georg

6
ฉันชอบข้อเสนอแนะเพื่อใช้ polyfill อย่างไรก็ตามรหัสตามที่เขียนยังคงล้มเหลวใน IE11 แม้จะมี polyfill เนื่องจากการใช้ฟังก์ชั่นลูกศร / แลมบ์ดา Re-เขียนเป็นindex = a.findIndex(function (x) { return x.prop2 == "yutu" })แก้ไขปัญหาเพื่อให้มีรหัส polyfill ที่ findIndex ทำงานใน IE11
ริก Glos

26

ฉันจะทำให้ดัชนีของวัตถุนั้นตรงกับเงื่อนไขได้อย่างไร (โดยไม่มีการวนซ้ำตามอาร์เรย์)

คุณไม่สามารถมีสิ่งที่ต้องทำซ้ำผ่านอาร์เรย์ (อย่างน้อยหนึ่งครั้ง)

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

var index;
yourArray.some(function(entry, i) {
    if (entry.prop2 == "yutu") {
        index = i;
        return true;
    }
});

ที่ใช้Array#someฟังก์ชั่นใหม่ (ish) ซึ่งวนรอบรายการในอาร์เรย์จนฟังก์ชั่นที่คุณให้มันกลับเป็นจริง ฟังก์ชั่นที่ฉันให้ไว้จะบันทึกดัชนีของรายการที่ตรงกันจากนั้นกลับtrueสู่การหยุดการวนซ้ำ

หรือแน่นอนเพียงแค่ใช้forวง ตัวเลือกการวนซ้ำแบบต่างๆของคุณครอบคลุมอยู่ในคำตอบอื่น ๆนี้

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

var prop2map = {};
yourArray.forEach(function(entry) {
    prop2map[entry.prop2] = entry;
});

(หรืออีกครั้งคุณสามารถใช้การforวนซ้ำหรือตัวเลือกอื่น ๆ ของคุณ )

จากนั้นถ้าคุณต้องการค้นหารายการด้วยprop2 = "yutu"คุณสามารถทำได้:

var entry = prop2map["yutu"];

ฉันเรียกสิ่งนี้ว่า "การสร้างดัชนีข้าม" โดยธรรมชาติถ้าคุณลบหรือเพิ่มรายการ (หรือเปลี่ยนprop2ค่าของพวกเขา) คุณจะต้องปรับปรุงวัตถุการทำแผนที่ของคุณเช่นกัน


ขอบคุณสำหรับคำอธิบาย! วิธีการแก้ปัญหากับ jQuery ชี้โดยthg435ทำในสิ่งที่ฉันต้องการ ...
แอมป์

21

สิ่งที่ TJ Crowder กล่าวว่าทุก ๆ ครั้งจะมีการทำซ้ำแบบซ่อนเร้นอยู่บ้างโดยที่lodashจะกลายเป็น:

var index = _.findIndex(array, {prop2: 'yutu'})

1
ในขณะที่คุณสามารถวนรอบหลาย ๆ วิธีเพื่อรับดัชนี Find Index เป็นทางออกที่ดีที่สุดแม้จะใช้ใน ES6 ในวิธีอาร์เรย์แบบดั้งเดิม
Kelly Milligan

13
var CarId = 23;

//x.VehicleId property to match in the object array
var carIndex = CarsList.map(function (x) { return x.VehicleId; }).indexOf(CarId);

และสำหรับหมายเลขอาเรย์พื้นฐานคุณยังสามารถทำได้:

var numberList = [100,200,300,400,500];
var index = numberList.indexOf(200); // 1

คุณจะได้รับ -1 หากไม่สามารถหาค่าในอาร์เรย์


11
var index;
yourArray.some(function (elem, i) {
    return elem.prop2 === 'yutu' ? (index = i, true) : false;
});

ทำซ้ำองค์ประกอบทั้งหมดของอาร์เรย์ มันจะส่งกลับทั้งดัชนีและจริงหรือเท็จถ้าเงื่อนไขไม่ตรงกัน

สำคัญคือค่าส่งคืนที่ชัดเจนของจริง (หรือค่าที่ผลบูลีนเป็นจริง) การมอบหมายครั้งเดียวไม่เพียงพอเนื่องจากดัชนีที่เป็นไปได้ที่มี 0 (บูลีน (0) === false) ซึ่งจะไม่ส่งผลให้เกิดข้อผิดพลาด แต่จะปิดใช้งานการแบ่งการวนซ้ำ

แก้ไข

เวอร์ชันที่สั้นกว่าของด้านบน:

yourArray.some(function (elem, i) {
    return elem.prop2 === 'yutu' && ~(index = i);
});

อักขระ ~ ทำอะไรในตัวอย่างที่สองของคุณ
serkan

@serkan มันเป็นตัวดำเนินการระดับบิตไม่ใช่|มันเป็นรุ่นสั้น ๆ ของการรับจากดัชนี (ด้วย -1) ผลลัพธ์ที่เป็นจริง / เท็จถ้ามีดัชนีอยู่
Nina Scholz

ขอบคุณ Nina หากไม่มีตัวอักษร ~ รหัสจะทำงานเหมือนเดิมใช่มั้ย
serkan

@serkan คำถามของคุณไม่ชัดเจน แต่ถ้าไม่มี~มันก็ไม่ทำงานเช่นนั้น
Nina Scholz

1
โอ้!!(index = 0)และ!!~(index = 0)แตกต่างแน่นอน ขอบคุณ!
serkan

4

คุณสามารถใช้Array.prototype.some ()ด้วยวิธีต่อไปนี้ (ดังที่ได้กล่าวไว้ในคำตอบอื่น ๆ ):

https://jsfiddle.net/h1d69exj/2/

function findIndexInData(data, property, value) {
    var result = -1;
    data.some(function (item, i) {
        if (item[property] === value) {
            result = i;
            return true;
        }
    });
    return result;
}
var data = [{prop1:"abc",prop2:"qwe"},{prop1:"bnmb",prop2:"yutu"},{prop1:"zxvz",prop2:"qwrq"}]



alert(findIndexInData(data, 'prop2', "yutu")); // shows index of 1

4

ฉันได้เห็นวิธีแก้ปัญหาต่าง ๆ ในข้างต้น

ที่นี่ฉันใช้ฟังก์ชันแผนที่เพื่อค้นหาดัชนีข้อความค้นหาในวัตถุอาร์เรย์

ฉันจะอธิบายคำตอบของฉันโดยใช้ข้อมูลนักเรียน

  • ขั้นตอนที่ 1 : สร้างวัตถุอาร์เรย์สำหรับนักเรียน (ไม่จำเป็นคุณสามารถสร้างวัตถุอาร์เรย์ของคุณเอง)
    var students = [{name:"Rambabu",htno:"1245"},{name:"Divya",htno:"1246"},{name:"poojitha",htno:"1247"},{name:"magitha",htno:"1248"}];

  • ขั้นตอนที่ 2 : สร้างตัวแปรเพื่อค้นหาข้อความ
    var studentNameToSearch = "Divya";

  • ขั้นตอนที่ 3 : สร้างตัวแปรเพื่อจัดเก็บดัชนีที่ตรงกัน (ที่นี่เราใช้ฟังก์ชั่นแผนที่เพื่อทำซ้ำ)
    var matchedIndex = students.map(function (obj) { return obj.name; }).indexOf(studentNameToSearch);

var students = [{name:"Rambabu",htno:"1245"},{name:"Divya",htno:"1246"},{name:"poojitha",htno:"1247"},{name:"magitha",htno:"1248"}];

var studentNameToSearch = "Divya";

var matchedIndex = students.map(function (obj) { return obj.name; }).indexOf(studentNameToSearch);

console.log(matchedIndex);

alert("Your search name index in array is:"+matchedIndex)


3
function findIndexByKeyValue(_array, key, value) {
    for (var i = 0; i < _array.length; i++) { 
        if (_array[i][key] == value) {
            return i;
        }
    }
    return -1;
}
var a = [
    {prop1:"abc",prop2:"qwe"},
    {prop1:"bnmb",prop2:"yutu"},
    {prop1:"zxvz",prop2:"qwrq"}];
var index = findIndexByKeyValue(a, 'prop2', 'yutu');
console.log(index);

1

ทำไมคุณไม่ต้องการวนซ้ำอย่างแน่นอน Array.prototype.forEachใหม่ยอดเยี่ยมสำหรับจุดประสงค์นี้!

คุณสามารถใช้แผนภูมิการค้นหาแบบไบนารีเพื่อค้นหาผ่านการโทรด้วยวิธีการเดียวหากคุณต้องการ นี่คือการนำต้นไม้ BTree และ Red black search ไปใช้อย่างเป็นระเบียบใน JS - https://github.com/vadimg/js_bintrees - แต่ฉันไม่แน่ใจว่าคุณสามารถค้นหาดัชนีได้ในเวลาเดียวกันหรือไม่


1

ขั้นตอนเดียวโดยใช้ Array.reduce () - no jQuery

var items = [{id: 331}, {id: 220}, {id: 872}];

var searchIndexForId = 220;
var index = items.reduce(function(searchIndex, item, index){
  if(item.id === searchIndexForId) { 
    console.log('found!');
    searchIndex = index;
  }
  return searchIndex;
}, null);

จะกลับมาnullหากไม่พบดัชนี


0
var list =  [
                {prop1:"abc",prop2:"qwe"},
                {prop1:"bnmb",prop2:"yutu"},
                {prop1:"zxvz",prop2:"qwrq"}
            ];

var findProp = p => {
    var index = -1;
    $.each(list, (i, o) => {
        if(o.prop2 == p) {
            index = i;
            return false; // break
        }
    });
    return index; // -1 == not found, else == index
}

0

Georg ได้กล่าวถึง ES6 แล้วว่ามี Array.findIndex สำหรับสิ่งนี้ และคำตอบอื่น ๆ คือวิธีแก้ปัญหาสำหรับ ES5 โดยใช้วิธี Array.some

อีกวิธีหนึ่งที่สง่างามสามารถ

var index;
for(index = yourArray.length; index-- > 0 && yourArray[index].prop2 !== "yutu";);

ในเวลาเดียวกันฉันต้องการจะเน้น Array.some อาจนำมาใช้กับไบนารีหรือเทคนิคการค้นหาที่มีประสิทธิภาพอื่น ๆ ดังนั้นมันอาจทำงานได้ดีกว่าสำหรับลูปในบางเบราว์เซอร์


0

ลองรหัสนี้

var x = [{prop1:"abc",prop2:"qwe"},{prop1:"bnmb",prop2:"yutu"},{prop1:"zxvz",prop2:"qwrq"}]
let index = x.findIndex(x => x.prop1 === 'zxvz')
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.