Trong một mảng các đối tượng, cách nhanh nhất để tìm chỉ mục của một đối tượng có thuộc tính khớp với tìm kiếm


135

Tôi đã lướt xung quanh một chút để cố gắng tìm ra một cách hiệu quả để làm điều này, nhưng không đi đến đâu. Tôi có một loạt các đối tượng trông như thế này:

array[i].id = some number;
array[i].name = some name;

Những gì tôi muốn làm là tìm INDEXES của các đối tượng có id bằng, ví dụ, một trong 0,1,2,3 hoặc 4. Tôi cho rằng tôi có thể làm một cái gì đó như:

var indexes = [];
for(i=0; i<array.length; i++) {
  (array[i].id === 0) ? { indexes[0] = i }
  (array[i].id === 1) ? { indexes[1] = i }
  (array[i].id === 2) ? { indexes[2] = i }
  (array[i].id === 3) ? { indexes[3] = i }
  (array[i].id === 4) ? { indexes[4] = i }
}

Trong khi điều này sẽ hoạt động, nó có vẻ khá tốn kém và chậm (chưa kể xấu xí), đặc biệt là nếu mảng.length có thể lớn. Bất cứ ý tưởng về làm thế nào để làm cho điều này lên một chút? Tôi đã nghĩ đến việc sử dụng Array.indexOf bằng cách nào đó nhưng tôi không thấy cách buộc cú pháp. Điều này

array.indexOf(this.id === 0);

ví dụ, trả về không xác định, vì nó có thể nên. Cảm ơn trước!


1
Nếu bạn có một mảng cũ đơn giản, tất cả những gì bạn có thể làm là lặp lại. Đó là mảng là gì, một loạt các đối tượng được sắp xếp theo chỉ mục mảng.
Dave Newton

2
Chỉ cần xem qua bài đăng này ngày hôm nay, đối với tất cả những người đến sau có một phương pháp mảng mới Array.prototype.findIndex()trong ECMAScript 2015. Câu trả lời được chấp nhận là tuyệt vời tho.
Conrad Lo

Tôi là người hâm mộ cú pháp ES6 (sử dụng polyfill, nếu cần hỗ trợ trên các trình duyệt cũ). ES7 + ES8 sẽ là tương lai
Fr0zenFyr

Câu trả lời:


391

Có thể bạn muốn sử dụng các hàm bậc cao hơn như "bản đồ". Giả sử bạn muốn tìm kiếm theo thuộc tính 'trường':

var elementPos = array.map(function(x) {return x.id; }).indexOf(idYourAreLookingFor);
var objectFound = array[elementPos];

9
Câu trả lời này rất hay vì nó thực sự trả lời câu hỏi bằng cách cung cấp chỉ mục :)
phản hồi

3
@ZeroAbsolute Hàm được áp dụng của bạn (được truyền vào bản đồ) có thể trả về một chuỗi băm sẽ cung cấp một khóa duy nhất cho mỗi kết hợp có thể được đưa ra bởi tiêu chí của bạn. Ví dụ : function hashf(el) { return String(el.id) + "_" + String(el.name); }. Đây chỉ là một gợi ý: elementPos = array.map(hashf(x)).indexOf(hash({id:3, name:'Pablo'}));Rõ ràng, hàm băm tôi cung cấp không hợp lệ cho tất cả các trường hợp vì '_'có thể tạo thành một phần của các giá trị của bạn nhưng nó chỉ là một ví dụ nhanh bạn có thể tìm ra các phương thức băm khác nhau.
Pablo Francisco Pérez Hidalgo

1
Điều này trở lại nếu nó không được tìm thấy? Tôi giả sử -1, chỉ tò mò. Tôi sẽ thử nghiệm.
Nathan C. Tresch

1
@ NathanC.Tresch Nó trả về -1 vì đó là indexOfgiá trị trả về khi không thể xác định giá trị đã cho.
Pablo Francisco Pérez Hidalgo

2
Xin chào mọi người thay vì sử dụng hai phương pháp, map, indexOfbạn chỉ có thể sử dụng một phương thức được gọi là findIndex....... Ví dụ:[{id:1},{id:2},{id:3},{id:4}].findIndex(function(obj){return obj.id == 3}) OR [{id:1},{id:2},{id:3},{id:4}].findIndex(obj => obj.id == 3)
Umair Ahmed

64

Cách đơn giản nhất và dễ nhất để tìm chỉ số phần tử trong mảng.

Cú pháp ES5: [{id:1},{id:2},{id:3},{id:4}].findIndex(function(obj){return obj.id == 3})

Cú pháp ES6: [{id:1},{id:2},{id:3},{id:4}].findIndex(obj => obj.id == 3)


4
Tôi tin rằng đây là giải pháp thanh lịch nhất. Đối với những người lo lắng về khả năng tương thích ngược, bạn có thể tìm thấy polyfill cho findIndextại developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/
trộm

2
Tôi nhận được một cảnh báo trong công cụ lint ES6 của mình rằng obj.id == 3toán tử được sử dụng ở đây có thể gây ra chuyển đổi loại không mong muốn, vì vậy hãy sử dụng obj.id === 3toán tử thay thế, để kiểm tra giá trị và loại bằng nhau.
thclark

1
Câu trả lời này nhanh hơn ít nhất 3,5 lần so với câu trả lời được chấp nhận ở trên. Sử dụng var elementPos = array.map(function(x) {return x.id; }).indexOf(idYourAreLookingFor);nó mất 0,03500000002532033 mili giây Sử dụng [{id:1},{id:2},{id:3},{id:4}].findIndex(obj => obj.id == 3)nó mất 0,00999999747378752 mili giây.
Ovidio Reyna

1
TRẢ LỜI NÀY là HIỆU QUẢ nhất vì nó không lặp lại toàn bộ mảng. Câu trả lời được chọn sẽ ánh xạ mảng hoàn chỉnh và sau đó find Index được ràng buộc lặp lại qua toàn bộ mảng một lần
Karun

26

Phương thức Array mới .filter () sẽ hoạt động tốt cho việc này:

var filteredArray = array.filter(function (element) { 
    return element.id === 0;
});

jQuery cũng có thể làm điều này với .grep ()

chỉnh sửa: điều đáng nói là cả hai chức năng này chỉ lặp đi lặp lại dưới mui xe, sẽ không có sự khác biệt hiệu suất đáng chú ý giữa chúng và lăn chức năng bộ lọc của riêng bạn, nhưng tại sao lại phát minh lại bánh xe.


+1, tôi luôn quên về các hàm được tích hợp như thế này trên các đối tượng.
Tejs

59
Điều này không trả về một chỉ mục.
Adam Grant

Điều này không trả lời câu hỏi cụ thể này, nhưng giúp tôi rất nhiều! Cảm ơn!
rochasdv

Điều này không trả về chỉ số.
Giàu

10

Nếu bạn quan tâm đến hiệu suất, đừng đi với tìm hoặc lọc hoặc ánh xạ hoặc bất kỳ phương pháp nào được thảo luận ở trên

Dưới đây là một ví dụ minh họa phương pháp nhanh nhất. ĐÂY là liên kết đến bài kiểm tra thực tế

Khối cài đặt

var items = []

for(var i = 0; i < 1000; i++) {
    items.push({id: i + 1})
}

var find = 523

Phương pháp nhanh nhất

var index = -1
for(var i = 0; i < items.length; i++) {
    if(items[i].id === find) {
        index = i;
        break;
    }
}

Phương pháp chậm hơn

items.findIndex(item => item.id === find)

Phương pháp SLOWEST

items.map(item => item.id).indexOf(find);

2
Cảm ơn đã cung cấp sự so sánh này! Điều thú vị là có bao nhiêu hiệu suất thay đổi - bao gồm phương pháp nào thay đổi nhanh hơn tùy thuộc vào trình duyệt / công cụ JavaScript nào được sử dụng để chạy chúng.
Iain Collins

1
Tôi nghĩ rằng điều này nên được đánh dấu là một câu trả lời. Điều này cho thấy cách nhanh nhất và chậm hơn.
Thuốc giảm đau

Trong điểm chuẩn của bạn, khối 2 (sử dụng find Index) thực sự nhanh hơn đối với tôi (trên Microsoft Edge Chromium 83.0.474.0)
rezadru

Khối 2 bây giờ cũng nhanh hơn trên chrome
cody mikol

8
array.forEach(function (elem, i) {  // iterate over all elements of array
    indexes[elem.id] = i;           // take the found id as index for the
});                                 // indexes array and assign i

kết quả là một danh sách tra cứu cho id. với id đã cho, chúng ta sẽ có được chỉ số của bản ghi.


6
var indices = [];
var IDs = [0, 1, 2, 3, 4];

for(var i = 0, len = array.length; i < len; i++) {
    for(var j = 0; j < IDs.length; j++) {
        if(array[i].id == ID) indices.push(i);
    }
}

6

Vì không có câu trả lời bằng cách sử dụng mảng thông thường find:

var one = {id: 1, name: 'one'};
var two = {id: 2, name:'two'}
var arr = [one, two] 

var found = arr.find((a) => a.id === 2)

found === two // true

arr.indexOf(found) // 1

3

Một cách mới sử dụng ES6

let picked_element = array.filter(element => element.id === 0);

picked_elementlà một mảng trong trường hợp này ...
Khỉ Heretic

3

const index = array.findIndex(item => item.id === 'your-id');

Điều này sẽ giúp bạn có được chỉ mục của mục trong mảng với id === your-id

array = [ {id:1}, {id:2} ];

const index = array.findIndex(item => item.id === 2);

console.log(index);


2

Âm thanh với tôi như bạn có thể tạo ra một trình vòng lặp đơn giản với một cuộc gọi lại để thử nghiệm. Thích như vậy:

function findElements(array, predicate)
{
    var matchingIndices = [];

    for(var j = 0; j < array.length; j++)
    {
        if(predicate(array[j]))
           matchingIndices.push(j);
    }

    return matchingIndices;
}

Sau đó, bạn có thể gọi như vậy:

var someArray = [
     { id: 1, text: "Hello" },
     { id: 2, text: "World" },
     { id: 3, text: "Sup" },
     { id: 4, text: "Dawg" }
  ];

var matchingIndices = findElements(someArray, function(item)
   {
        return item.id % 2 == 0;
   });

// Should have an array of [1, 3] as the indexes that matched

2

Điều chỉnh câu trả lời của Tejs cho mongoDB và Robomongo tôi đã thay đổi

matchingIndices.push(j);

đến

matchingIndices.push(NumberInt(j+1));

2

Sử dụng mapchức năng ES6 :

let idToFind = 3;
let index = someArray.map(obj => obj.id).indexOf(idToFind);

2

Để tóm tắt tất cả các câu trả lời tuyệt vời ở trên và bổ sung câu trả lời của tôi liên quan đến việc tìm tất cả các chỉ mục xảy ra từ một số nhận xét.

  1. Để trả về chỉ số của lần xuất hiện đầu tiên.

const array = [{ id: 1 }, { id: 2 }, { id: 3 }, { id: 4 }, { id: 2 }];
const idYourAreLookingFor = 2;

//ES5 
//Output: 1
array.map(function (x) { return x.id; }).indexOf(idYourAreLookingFor);

//ES6 
//Output: 1
array.findIndex(obj => obj.id === idYourAreLookingFor);

  1. Để trả về mảng chỉ mục của tất cả các lần xuất hiện, sử dụng giảm.

const array = [{ id: 1 }, { id: 2 }, { id: 3 }, { id: 4 }, { id: 2 }]
const idYourAreLookingFor = 2;

//ES5
//Output: [1, 4]
array.reduce(function (acc, obj, i) {
  if (obj.id === idYourAreLookingFor)
    acc.push(i);
  return acc;
}, []);

//ES6
//Output: [1, 4]
array.reduce((acc, obj, i) => (obj.id === idYourAreLookingFor) ? acc.concat(i) : acc, [])


0

Khi tôi chưa thể nhận xét, tôi muốn hiển thị giải pháp tôi đã sử dụng dựa trên phương pháp Umair Ahmed đã đăng, nhưng khi bạn muốn tìm kiếm khóa thay vì giá trị:

[{"a":true}, {"f":true}, {"g":false}]
.findIndex(function(element){return Object.keys(element)[0] == "g"});

Tôi hiểu rằng nó không trả lời câu hỏi mở rộng, nhưng tiêu đề không chỉ định những gì mong muốn từ mỗi đối tượng, vì vậy tôi muốn khiêm tốn chia sẻ điều này để tiết kiệm đau đầu cho những người khác trong tương lai, trong khi tôi hủy bỏ nó có thể không phải là giải pháp nhanh nhất.


0

Tôi đã tạo một tiện ích nhỏ gọi là siêu mảng , nơi bạn có thể truy cập các mục trong một mảng bằng một mã định danh duy nhất có độ phức tạp O (1). Thí dụ:

const SuperArray = require('super-array');

const myArray = new SuperArray([
  {id: 'ab1', name: 'John'},
  {id: 'ab2', name: 'Peter'},
]);

console.log(myArray.get('ab1')); // {id: 'ab1', name: 'John'}
console.log(myArray.get('ab2')); // {id: 'ab2', name: 'Peter'}

Bạn có thể muốn đọc Làm thế nào để cung cấp các thư viện nguồn mở cá nhân? trước khi đăng bài này ở mọi nơi
Martijn Pieters

@MartijnPieters Tôi chỉ đăng nó cho một vài câu hỏi có liên quan và dự án là MIT miễn phí, vậy thỏa thuận là gì? Có lẽ bạn có thể chịu đựng hơn một chút.
patotoma

0
var test = [
  {id:1, test: 1},
  {id:2, test: 2},
  {id:2, test: 2}
];

var result = test.findIndex(findIndex, '2');

console.log(result);

function findIndex(object) {
  return object.id == this;
}

sẽ trả về chỉ số 1 (Chỉ hoạt động trong ES 2016)


0

Tôi thích phương pháp này vì nó dễ dàng so sánh với bất kỳ giá trị nào trong đối tượng cho dù nó được lồng sâu đến đâu.

 while(i<myArray.length && myArray[i].data.value!==value){
  i++; 
}
// i now hows the index value for the match. 
 console.log("Index ->",i );
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.