Lấy chỉ mục của đối tượng bên trong một mảng, khớp với một điều kiện


322

Tôi có một mảng như thế này:

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

Làm thế nào tôi có thể có được chỉ mục của đối tượng phù hợp với một điều kiện, mà không lặp lại trên toàn bộ mảng?

Ví dụ, được đưa ra prop2=="yutu", tôi muốn có được chỉ mục 1.

Tôi đã thấy .indexOf()nhưng nghĩ rằng nó được sử dụng cho các mảng đơn giản như ["a1","a2",...]. Tôi cũng đã kiểm tra $.grep()nhưng điều này trả về các đối tượng, không phải chỉ mục.

Câu trả lời:


733

Kể từ năm 2016, bạn phải sử dụng Array.findIndex(tiêu chuẩn ES2015 / ES6) cho việc này:

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

console.log(index);

Nó được hỗ trợ trong Google Chrome, Firefox và Edge. Đối với Internet Explorer, có một polyfill trên trang được liên kết.

Ghi chú hiệu suất

Các cuộc gọi chức năng rất tốn kém, do đó với các mảng thực sự lớn, một vòng lặp đơn giản sẽ thực hiện tốt hơn nhiều so với 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');

Như với hầu hết các tối ưu hóa, điều này nên được áp dụng cẩn thận và chỉ khi thực sự cần thiết.


3
Tôi không thấy sự cần thiết cho một mảng tạm thời ở đây. Chỉ cần sử dụng thực tế là hàm iterator đóng trên ngữ cảnh và sử dụng một biến. Ngoài ra, phiên bản không phải là jQuery không hoạt động (giả sử nó được tìm thấy tại chỉ mục 0?). Cả hai giải pháp đều lặp đi lặp lại nhiều hơn yêu cầu, ít hơn lý tưởng nếu mảng lớn (mặc dù tỷ lệ của nó quá lớn, con người sẽ nhận thấy là thấp, trừ khi việc tra cứu đang diễn ra rất nhiều ).
TJ Crowder

@ Jun435: Vẫn nghĩ rằng đó là một chút của máy Rube Goldberg, nơi một đòn bẩy đơn giản sẽ thực hiện thủ thuật. :-) Nhưng này, nó hoạt động!
TJ Crowder

4
Bạn có thể giải thích cách làm x => x.prop2=="yutu"việc với find Index () không?
Abhay Pai

5
@ AbhayPai: nó giống nhưfunction(x) { return x.prop2=="yutu" }
georg

6
Tôi thích đề xuất sử dụng polyfill. Tuy nhiên, mã như được viết vẫn thất bại trong IE11 ngay cả với polyfill do sử dụng hàm mũi tên / lambda. Viết lại như đã index = a.findIndex(function (x) { return x.prop2 == "yutu" })khắc phục sự cố để với mã polyfill, find Index hoạt động trong IE11
Rick Glos

26

Làm thế nào tôi có thể có được chỉ mục của đối tượng tha phù hợp với một điều kiện (không lặp đi lặp lại dọc theo mảng)?

Bạn không thể, một cái gì đó phải lặp qua mảng (ít nhất một lần).

Nếu điều kiện thay đổi nhiều, thì bạn sẽ phải lặp lại và nhìn vào các đối tượng trong đó để xem chúng có khớp với điều kiện không. Tuy nhiên, trên một hệ thống có các tính năng ES5 (hoặc nếu bạn cài đặt shim), việc lặp lại đó có thể được thực hiện khá chính xác:

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

Đó là sử dụng mới (ish) Array#somechức năng , trong đó vòng qua các mục trong mảng cho đến khi chức năng bạn cho nó trả về true. Hàm tôi đã cung cấp cho nó lưu chỉ mục của mục phù hợp, sau đó quay lại trueđể dừng lặp.

Hoặc tất nhiên, chỉ cần sử dụng một forvòng lặp. Các tùy chọn lặp khác nhau của bạn được đề cập trong câu trả lời khác này .

Nhưng nếu bạn luôn sử dụng cùng một thuộc tính cho tra cứu này và nếu các giá trị thuộc tính là duy nhất, bạn có thể lặp lại chỉ một lần và tạo một đối tượng để ánh xạ chúng:

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

(Hoặc, một lần nữa, bạn có thể sử dụng một forvòng lặp hoặc bất kỳ tùy chọn nào khác của bạn .)

Sau đó, nếu bạn cần tìm mục với prop2 = "yutu", bạn có thể làm điều này:

var entry = prop2map["yutu"];

Tôi gọi đây là "lập chỉ mục chéo" mảng. Đương nhiên, nếu bạn xóa hoặc thêm các mục (hoặc thay đổi prop2giá trị của chúng ), bạn cũng cần cập nhật đối tượng ánh xạ của mình.


Cảm ơn đã giải thích! Giải pháp với jQuery được chỉ ra bằng cách thg435làm những gì tôi muốn ...
amp

21

Những gì TJ Crowder đã nói, mọi cách sẽ có một số loại lặp lại ẩn, với lodash điều này trở thành:

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

1
trong khi bạn chỉ có thể lặp qua nhiều cách khác nhau để lấy chỉ mục, hãy tìm Index là giải pháp tốt nhất, thậm chí được áp dụng trong ES6 vào các phương thức mảng gốc
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);

Và đối với các số mảng cơ bản, bạn cũng có thể làm điều này:

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

Bạn sẽ nhận được -1 nếu không thể tìm thấy giá trị trong mảng.


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

Lặp lại tất cả các yếu tố của mảng. Nó trả về chỉ số và đúng hoặc sai nếu điều kiện không khớp.

Quan trọng là giá trị trả về rõ ràng của true (hoặc giá trị mà kết quả boolean là true). Việc gán đơn là không đủ, vì chỉ số có thể có 0 (Boolean (0) === false), điều này sẽ không gây ra lỗi nhưng vô hiệu hóa việc ngắt lặp.

Biên tập

Một phiên bản thậm chí ngắn hơn ở trên:

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

Nhân vật ~ làm gì trong đoạn trích thứ hai của bạn?
serkan

@serkan, nó là một Bitwise NOT| điều hành, nó là một phiên bản ngắn của nhận được từ một chỉ số (với -1) một truthy / falsy kết quả, nếu một chỉ số tồn tại.
Nina Scholz

cảm ơn Nina, không có ký tự ~, mã hoạt động như vậy, phải không?
serkan

@serkan, câu hỏi của bạn không rõ ràng, nhưng không có ~nó không hoạt động như thế.
Nina Scholz

1
oh, !!(index = 0)!!~(index = 0)sự khác biệt thực sự. Cảm ơn!
serkan

4

Bạn có thể sử dụng Array.prototype.some () theo cách sau (như được đề cập trong các câu trả lời khác):

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

Tôi đã thấy nhiều giải pháp ở trên.

Ở đây tôi đang sử dụng chức năng ánh xạ để tìm chỉ mục của văn bản tìm kiếm trong một đối tượng mảng.

Tôi sẽ giải thích câu trả lời của tôi bằng cách sử dụng dữ liệu của sinh viên.

  • Bước 1 : tạo đối tượng mảng cho sinh viên (tùy chọn bạn có thể tạo đối tượng mảng của riêng mình).
    var students = [{name:"Rambabu",htno:"1245"},{name:"Divya",htno:"1246"},{name:"poojitha",htno:"1247"},{name:"magitha",htno:"1248"}];

  • Bước 2 : Tạo biến để tìm kiếm văn bản
    var studentNameToSearch = "Divya";

  • Bước 3 : Tạo biến để lưu chỉ mục phù hợp (ở đây chúng tôi sử dụng chức năng bản đồ để lặp lại).
    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

Tại sao bạn không muốn lặp lại chính xác? Array.prototype.forEach mới là tuyệt vời cho mục đích này!

Bạn có thể sử dụng Cây tìm kiếm nhị phân để tìm thông qua một cuộc gọi phương thức duy nhất nếu bạn muốn. Đây là một triển khai gọn gàng của cây Tìm kiếm BTree và Đỏ đen trong JS - https://github.com/vadimg/js_bintrees - nhưng tôi không chắc liệu bạn có thể tìm thấy chỉ mục cùng một lúc không.


1

Một bước sử dụng Array.reduce () - không có 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);

sẽ trở lại nullnếu không tìm thấy chỉ mục.


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 đã đề cập ES6 có Array.find Index cho việc này. Và một số câu trả lời khác là cách giải quyết cho ES5 bằng phương thức Array.some.

Một cách tiếp cận thanh lịch hơn có thể là

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

Đồng thời tôi muốn nhấn mạnh, Array.some có thể được triển khai bằng kỹ thuật tìm kiếm nhị phân hoặc hiệu quả khác. Vì vậy, nó có thể hoạt động tốt hơn cho vòng lặp trong một số trình duyệt.


0

Hãy thử mã này

var x = [{prop1:"abc",prop2:"qwe"},{prop1:"bnmb",prop2:"yutu"},{prop1:"zxvz",prop2:"qwrq"}]
let index = x.findIndex(x => x.prop1 === 'zxvz')
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.