Câu hỏi Tìm đối tượng theo id trong một mảng các đối tượng JavaScript


Tôi có một mảng:

myArray = [{'id':'73','foo':'bar'},{'id':'45','foo':'bar'}, etc.]

Tôi không thể thay đổi cấu trúc của mảng. Tôi đang được thông qua một id của 45và tôi muốn 'bar' cho đối tượng đó trong mảng.

Làm thế nào để làm điều này trong JavaScript hoặc sử dụng jQuery?


1109
2017-09-09 15:42


gốc




Các câu trả lời:


Sử dụng find() phương pháp:

myArray.find(x => x.id === '45').foo;

Từ MDN:

Các find() phương thức trả về một giá trị trong mảng, nếu một phần tử trong mảng thỏa mãn hàm kiểm tra được cung cấp. Nếu không thì undefined Được trả lại.


Nếu bạn muốn tìm mục lục thay vào đó, hãy sử dụng findIndex():

myArray.findIndex(x => x.id === '45');

Từ MDN:

Các findIndex() phương thức trả về chỉ mục của phần tử đầu tiên trong mảng đáp ứng chức năng kiểm tra được cung cấp. Nếu không -1 được trả về.


Nếu bạn muốn nhận được một mảng các phần tử phù hợp, hãy sử dụng filter() thay vào đó:

myArray.filter(x => x.id === '45');

Điều này sẽ trả về một mảng các đối tượng. Nếu bạn muốn nhận được một mảng foo các thuộc tính, bạn có thể làm điều này với map() phương pháp:

myArray.filter(x => x.id === '45').map(x => x.foo);

Lưu ý phụ: các phương pháp như find() hoặc là filter()chức năng mũi tên không được hỗ trợ bởi các trình duyệt cũ hơn (như IE), vì vậy nếu bạn muốn hỗ trợ các trình duyệt này, bạn nên chuyển mã của mình bằng cách sử dụng Babel (với polyfill).


433
2018-02-14 21:11



Đối với nhiều điều kiện thử nghiệm do đó nó sẽ là một cái gì đó như: myArray.find (x => x.id === '45' && x.color == 'red'). - Apqu
Đối với tôi, câu trả lời tốt nhất cho đến nay. Không cần jQuery không tạo mảng mới. - Arthur Cantarela
myArray.find (x => x.id === '45') nó không hoạt động trên mac PC - Govinda Rajbhar
@ T.J.Crowder Tôi không nghĩ rằng đó là một ý tưởng tốt để sao chép-dán polyfills từ MDN vào mã của bạn; thay vào đó, bạn nên sử dụng các gói npm với các polyfills. Và Babel không bao gồm các polyfills cho các tính năng ES2015 +, trong babel-polyfill gói. - Michał Perłakowski
@ MichałPerłakowski - tôi đã nói "(Babel cũng có thể bao gồm các polyfills cho một số thứ)" Và đồng ý, polyfilling đã di chuyển kể từ khi sao chép và dán từ MDN. :-) - T.J. Crowder


Vì bạn đã sử dụng jQuery, bạn có thể sử dụng grep chức năng được thiết kế để tìm kiếm một mảng:

var result = $.grep(myArray, function(e){ return e.id == id; });

Kết quả là một mảng với các mục được tìm thấy. Nếu bạn biết rằng đối tượng luôn ở đó và nó chỉ xảy ra một lần, bạn có thể sử dụng result[0].foo để có được giá trị. Nếu không, bạn nên kiểm tra độ dài của mảng kết quả. Thí dụ:

if (result.length == 0) {
  // not found
} else if (result.length == 1) {
  // access the foo property using result[0].foo
} else {
  // multiple items found
}

1421
2017-09-09 15:54



Nó sẽ an toàn hơn để sử dụng === thay vì ==, để tránh các vấn đề lạ với JavaScript == nhà điều hành. - Vicky Chijwani
@VickyChijwani: Có bất kỳ vấn đề nào khi so sánh chuỗi với chuỗi không? - Guffa
Vâng, nếu bạn chắc chắn rồi chắc chắn rằng cả hai e.id và id sẽ là chuỗi, tôi cho rằng nó là ok để sử dụng ==. Nhưng nếu bạn không chắc chắn, bạn có thể gặp vấn đề (kể từ '' == 0 Là true nhưng '' === 0 Là false). Chưa kể === dường như nhanh hơn (stackoverflow.com/questions/359494/…). - Vicky Chijwani
Về cơ bản tôi luôn sử dụng === bởi vì nó hoạt động chính xác như == bằng các ngôn ngữ lập trình khác. Tôi xem xét == không tồn tại trong JavaScript. - Vicky Chijwani
@de. Nhiều câu trả lời ở đây cung cấp hành vi dự định khi tìm kiếm các giá trị duy nhất; bạn về cơ bản có thể nhận ra chúng bằng thực tế là chúng quay trở lại hoặc thoát khỏi vòng lặp của chúng sớm (hoặc hướng dẫn một cấu trúc cấp thấp hơn để ngừng lặp lại). Xem câu trả lời của JaredPar cho một ví dụ kinh điển, và nhận xét của Aaronius về câu trả lời đó cho cùng một cái nhìn sâu sắc. Nói chung, mọi người phân biệt giữa chức năng "lọc" và "tìm" theo cách này, nhưng thuật ngữ khác nhau. Mặc dù hiệu quả hơn, đây vẫn là một tìm kiếm tuyến tính, vì vậy nếu bạn muốn sử dụng một bảng băm, hãy xem câu trả lời của Aaron Digulla (hãy cẩn thận về các chi tiết impl). - tne


Một giải pháp khác là tạo đối tượng tra cứu:

var lookup = {};
for (var i = 0, len = array.length; i < len; i++) {
    lookup[array[i].id] = array[i];
}

... now you can use lookup[id]...

Điều này đặc biệt thú vị nếu bạn cần thực hiện nhiều lần tra cứu.

Điều này sẽ không cần nhiều bộ nhớ hơn vì các ID và đối tượng sẽ được chia sẻ.


344
2017-09-09 15:50



Chính xác những gì tôi đang tìm kiếm. Buồn cười cách tôi cố gắng làm phức tạp nó bằng cách cố gắng lặp lại từng lần, xóa từng mục khỏi danh sách khi tôi tìm thấy nó khi tôi chỉ cần thay đổi dữ liệu nhận được từ CouchDB và biến nó thành định dạng hữu ích cho tôi nhu cầu. 1 thưa ngài! - slickplaid
điều này là thông minh. Tôi không thể tưởng tượng được những người khác bị thuyết phục như thế nào bằng cách xem xét tất cả các mảng cho mỗi lần sử dụng. - Aladdin Mhemed
Miễn là bạn không dựa vào thứ tự của các thuộc tính: stackoverflow.com/questions/4886314/… - Marle1
Đang sử dụng một break; trong vòng lặp một lựa chọn tốt / cải thiện nếu bạn biết chỉ có một đối tượng để tìm? - irJvV
@irJvV: Không, điều đó không có ý nghĩa gì cả. Đoạn mã trên rất hữu ích nếu bạn cần thực hiện nhiều lần tra cứu. Nếu bạn nhìn chỉ một lần, sau đó tạo lookup đối tượng là một sự lãng phí thời gian. - Aaron Digulla


ECMAScript 2015 cung cấp tìm thấy() phương pháp trên mảng:

var myArray = [
 {id:1, name:"bob"},
 {id:2, name:"dan"},
 {id:3, name:"barb"},
]

// grab the Array item which matchs the id "2"
var item = myArray.find(item => item.id === 2);

// print
console.log(item.name);

Nó hoạt động mà không có thư viện bên ngoài. Nhưng nếu bạn muốn hỗ trợ trình duyệt cũ hơn bạn có thể muốn bao gồm polyfill này.


147
2018-02-10 22:32



Có thể gây ra nó vẫn có vẻ rất thử nghiệm và không nhiều trình duyệt hỗ trợ nó, developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/… - lejonl
Điều này có thể được đơn giản hóa thành myArray.find(d=>d.id===45).foo;. - Shaggy
@Shaggy hoặc thậm chí myArray.find(({ id }) => id === 45).foo. Nhưng đây là một câu trả lời cũ đã được viết trước khi cú pháp ES2015 cũng được hỗ trợ như bây giờ. @ Gothdo’s câu trả lời hiện là cập nhật nhất trong chuỗi. - Rúnar Berg
@Shaggy nếu .find () trả về undefined, sau đó tối ưu hóa của bạn sẽ ném một lỗi. Vì vậy, giải pháp này có thể được sử dụng chỉ trong trường hợp một trận đấu được đảm bảo. - Herbert Peters
@ HerbertPeters Nếu bạn muốn chắc chắn rằng bạn có thể đồng ý kiểm tra null, điều này sẽ thực sự dễ dàng với chuỗi tùy chọn: myArray.find(d => d.id === 45)?.foo. - Rúnar Berg


Underscore.js có một phương pháp tốt đẹp cho điều đó:

myArray = [{'id':'73','foo':'bar'},{'id':'45','foo':'bar'},etc.]
obj = _.find(myArray, function(obj) { return obj.id == '45' })

138
2017-11-22 12:52



Đối với các bản ghi, Lo-Dash (thường có nhiều hiệu năng hơn Underscore) có một phương pháp tương tự. Tài liệu tại đây: lodash.com/docs#find - user456584
Nếu bạn đang mong đợi chỉ có một đối tượng, thì việc sử dụng findWhere sẽ hiệu quả hơn sau khi tìm thấy một kết quả, tìm kiếm sẽ không đi xa hơn nữa. - Foreever
@Foreever Từ các tài liệu của _.find: "Hàm trả về ngay sau khi nó tìm thấy một phần tử có thể chấp nhận được và không duyệt qua toàn bộ danh sách." - GijsjanB


Tôi nghĩ rằng cách dễ nhất sẽ là như sau, nhưng nó sẽ không hoạt động trên Internet Explorer 8 (hoặc cũ hơn):

var result = myArray.filter(function(v) {
    return v.id === '45'; // Filter out the appropriate one
})[0].foo; // Get result and access the foo property

123
2017-09-09 15:46



Tôi tò mò, có bất kỳ lợi thế hiệu suất nào ở đây so với thông thường không for? - Igor Zinov'yev
@Igor Zinov'yev: Vâng, chắc chắn có những tác động hiệu suất với những công cụ mảng ES5 đó. Một hàm riêng biệt được thực hiện cho mỗi phần tử, vì vậy nó sẽ không thực sự nhanh so với một phần tử trực tiếp for vòng lặp. - pimvdb
Vì vậy, bạn đang nói rằng nó sẽ chậm hơn? Ngoài ra, nó sẽ luôn quét toàn bộ mảng, theo như tôi thấy, trong khi for vòng lặp sẽ kết thúc vào trận đấu đầu tiên. - Igor Zinov'yev
@Igor Zinov'yev: Vâng, đó là một giải pháp ngây thơ, tôi thừa nhận. - pimvdb
Nếu bạn cần hỗ trợ cho IE8, chỉ cần thả phần này vào: stackoverflow.com/questions/7153470/… - Adam Grant


Hãy thử những điều sau

function findById(source, id) {
  for (var i = 0; i < source.length; i++) {
    if (source[i].id === id) {
      return source[i];
    }
  }
  throw "Couldn't find object with id: " + id;
}

64
2017-09-09 15:45



Điều này không xứng đáng với câu trả lời của riêng mình, nhưng trong các trình duyệt hiện đại, giải pháp này có thể được viết như sau: jsfiddle.net/rwaldron/j3vST - Rick
Nếu bạn đang sử dụng hiệu quả, lưu ý rằng ví dụ này có thể nhanh hơn sử dụng filter () (xem ví dụ của Rick) vì nó trả về khi nó tìm thấy mục phù hợp đầu tiên trong khi filter () tiếp tục chạy qua toàn bộ mảng ngay cả sau khi tìm kiếm trận đấu. Điều này cũng không có chi phí tạo ra một mảng bổ sung hoặc gọi một hàm cho mỗi mục. - Aaronius
@ Rick, điều thú vị nhất về câu trả lời đó rõ ràng là bạn có thể thêm bảng điều khiển firebug vào cửa sổ đầu ra trong jsFiddle. Điều này tốt hơn rất nhiều so với việc ghi nhật ký và yêu cầu người khác mở giao diện điều khiển để xem đầu ra. Tuyệt vời! - KyleMit
Vì không ai đã đề cập đến nó cho đến nay, tôi muốn thêm rằng AngularJS cũng có một bộ lọc phương pháp. - Eno
@JaredPar stackoverflow.com/questions/44550439/… - Valay


myArray.filter(function(a){ return a.id == some_id_you_want })[0]

42
2018-04-16 17:31



Hoạt động cho IE9 + kangax.github.io/compat-table/es5/#Array.prototype.filter - Justin
Ployfill cho các trình duyệt cũ hơn: developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/… - Justin
@ Danilo làm thế nào tôi có thể tìm kiếm trong đối tượng lồng nhau? stackoverflow.com/questions/44550439/… - Valay


Một phiên bản chung và linh hoạt hơn của hàm findById ở trên:

// array = [{key:value},{key:value}]
function objectFindByKey(array, key, value) {
    for (var i = 0; i < array.length; i++) {
        if (array[i][key] === value) {
            return array[i];
        }
    }
    return null;
}

var array = [{'id':'73','foo':'bar'},{'id':'45','foo':'bar'}];
var result_obj = objectFindByKey(array, 'id', '45');

30
2017-07-13 20:34





Bạn có thể sử dụng bộ lọc,

  function getById(id, myArray) {
    return myArray.filter(function(obj) {
      if(obj.id == id) {
        return obj 
      }
    })[0]
  }

get_my_obj = getById(73, myArray);

13
2017-09-13 09:43



@TobiasBeuving - Một trong những sử dụng Array.find () là đồng bằng JS quá và nên dừng lại trên đầu tiên tìm thấy như vậy sẽ có hiệu quả hơn. - Adrian Lynch


Bạn có thể nhận được điều này một cách dễ dàng bằng cách sử dụng bản đồ() chức năng:

myArray = [{'id':'73','foo':'bar'},{'id':'45','foo':'bar'}];

var found = $.map(myArray, function(val) {
    return val.id == 45 ? val.foo : null;
});

//found[0] == "bar";

Ví dụ làm việc: http://jsfiddle.net/hunter/Pxaua/


13
2017-09-09 15:46



Tôi quên mất thực tế là jQuery map tự động xóa null các yếu tố. Nghe có vẻ gây hiểu lầm cho tôi và với khái niệm chung về mapvì kết quả không giống với độ dài của bộ sưu tập gốc. - MaxArt