Làm cách nào để tìm một giá trị trong một mảng đối tượng trong JavaScript?


90

Tôi có một mảng các đối tượng:

Object = {
   1 : { name : bob , dinner : pizza },
   2 : { name : john , dinner : sushi },
   3 : { name : larry, dinner : hummus }
}

Tôi muốn có thể tìm kiếm đối tượng / mảng mà khóa là "bữa tối" và xem nó có khớp với "sushi" hay không.

Tôi biết jQuery có $ .inArray, nhưng nó dường như không hoạt động trên các mảng đối tượng. Hoặc có thể tôi nhầm. indexOf dường như cũng chỉ hoạt động ở một cấp độ mảng.

Không có chức năng hoặc mã hiện có cho điều này?


Điều này đã được hỏi trước đây. Bạn phải viết hàm của riêng mình hoặc sử dụng một số thư viện khác.
Felix Kling

1
Xin lưu ý rằng Objectđược dành riêng trong Javascript, Objectlà đối tượng đối tượng, tức là mẹ của tất cả các đối tượng.
adamse ngày

1
câu hỏi và câu trả lời được chấp nhận không liên quan đến mảng nhiều chiều mà liên quan đến việc lọc mảng 1 chiều theo giá trị thuộc tính của các mục của nó. => Họ không giải quyết được vấn đề của tôi "tìm một giá trị trong mảng nhiều chiều".
Martin Schneider,

Câu trả lời:


211

Nếu bạn có một mảng chẳng hạn như

var people = [
  { "name": "bob", "dinner": "pizza" },
  { "name": "john", "dinner": "sushi" },
  { "name": "larry", "dinner": "hummus" }
];

Bạn có thể sử dụng filterphương thức của một đối tượng Array:

people.filter(function (person) { return person.dinner == "sushi" });
  // => [{ "name": "john", "dinner": "sushi" }]

Trong các triển khai JavaScript mới hơn, bạn có thể sử dụng biểu thức hàm:

people.filter(p => p.dinner == "sushi")
  // => [{ "name": "john", "dinner": "sushi" }]

Bạn có thể tìm kiếm những người đã "dinner": "sushi"sử dụngmap

people.map(function (person) {
  if (person.dinner == "sushi") {
    return person
  } else {
    return null
  }
}); // => [null, { "name": "john", "dinner": "sushi" }, null]

hoặc một reduce

people.reduce(function (sushiPeople, person) {
  if (person.dinner == "sushi") {
    return sushiPeople.concat(person);
  } else {
    return sushiPeople
  }
}, []); // => [{ "name": "john", "dinner": "sushi" }]

Tôi chắc rằng bạn có thể tổng quát điều này thành các khóa và giá trị tùy ý!


7
Chỉ cần lưu ý rằng các giải pháp này là một phần của ECMAScript 5 và không được hỗ trợ trong IE8. kangax.github.com/es5-compat-table Nhiều khi tôi thích câu trả lời của @ adamse hơn, alex's thân thiện với "trình duyệt cũ" hơn. Không chắc chắn về hiệu suất mặc dù.
EasyCo

@SalmanA - cũng không phải câu hỏi hoặc giải pháp đề cập đến jQuery. Bộ lọc javascript () được sử dụng, không jQuery cụ thể $ .filter () - tutorialspoint.com/javascript/array_filter.htm
Tapirboy

Như đã đề cập bởi EasyCo, chức năng bộ lọc không được hỗ trợ trong IE8. Tuy nhiên, nó dễ dàng được thêm vào nguyên mẫu Array và do đó có thể sử dụng được trong bất kỳ trình duyệt nào có chức năng nhỏ ở đầu tập lệnh của bạn. Điều này được nêu trong tài liệu bộ lọc . Nó cung cấp chức năng chính xác được chỉ định trong ECMA-262, vì vậy nó thực sự giống như vậy.
dallin

1
Tôi vừa thêm một câu trả lời sử dụng grepphương thức của jQuery . Có thể có ý nghĩa khi cuộn vào câu trả lời của bạn vì nó có cùng khái niệm như những gì bạn đang làm, nhưng phụ thuộc vào jQuery và thân thiện với trình duyệt tồi.
Zach Lysobey

Có lý do gì khiến tôi tiếp tục gặp lỗi tham chiếu với biến trả về của mình không? Tôi cố gắng đầu hai câu trả lời trở về "x '' và nó tiếp tục nói rằng nó là undefined ...
Evan Lalo

18

jQuery có một phương thức tích jQuery.grephợp hoạt động tương tự như filterhàm ES5 từ Câu trả lời của @ adamse và sẽ hoạt động tốt trên các trình duyệt cũ hơn.

Sử dụng ví dụ của adamse:

var peoples = [
  { "name": "bob", "dinner": "pizza" },
  { "name": "john", "dinner": "sushi" },
  { "name": "larry", "dinner": "hummus" }
];

bạn có thể làm như sau

jQuery.grep(peoples, function (person) { return person.dinner == "sushi" });
  // => [{ "name": "john", "dinner": "sushi" }]

10
var getKeyByDinner = function(obj, dinner) {
    var returnKey = -1;

    $.each(obj, function(key, info) {
        if (info.dinner == dinner) {
           returnKey = key;
           return false; 
        };   
    });

    return returnKey;       

}

jsFiddle .

Miễn -1là không bao giờ là một khóa hợp lệ.


gần như ủng hộ cái này, nhưng không có lời giải thích trong bài đăng.
mickmackusa

10

Nếu bạn định thực hiện tìm kiếm này thường xuyên, hãy xem xét việc thay đổi định dạng của đối tượng để bữa tối thực sự là chìa khóa. Điều này giống như việc gán một khóa cụm chính trong một bảng cơ sở dữ liệu. Ví dụ:

Obj = { 'pizza' : { 'name' : 'bob' }, 'sushi' : { 'name' : 'john' } }

Bây giờ bạn có thể dễ dàng truy cập nó như thế này: Object['sushi']['name']

Hoặc nếu đối tượng thực sự đơn giản như vậy (chỉ là 'tên' trong đối tượng), bạn chỉ cần thay đổi nó thành:

Obj = { 'pizza' : 'bob', 'sushi' : 'john' }

Và sau đó truy cập vào nó như: Object['sushi'].

Rõ ràng là không phải lúc nào cũng có thể hoặc là lợi thế của bạn để cấu trúc lại đối tượng dữ liệu của bạn như thế này, nhưng vấn đề là, đôi khi câu trả lời tốt nhất là xem xét liệu đối tượng dữ liệu của bạn có được cấu trúc theo cách tốt nhất hay không. Tạo khóa như thế này có thể nhanh hơn và tạo mã sạch hơn.


1
Yêu bạn trả lời, nhưng tôi thấy có vấn đề với cú pháp: của tôi chỉ hoạt động như thế này: obj = {"pizza": {"name": "bob"}, "sushi": {"name": "john"}} alert ( obj ['pizza'] ['name']); nhưng vẫn. cảm ơn! tìm thấy những gì tôi đang tìm kiếm! )
aleXela

@alexela Cảm ơn alexela! Tôi đã cập nhật câu trả lời của mình với sự quan sát sắc sảo của bạn! Tôi vừa sao chép ví dụ trong bài đăng của OP và bỏ qua việc thêm dấu ngoặc kép, nhưng bạn nói đúng - nó sẽ không hoạt động trừ khi ít nhất có dấu ngoặc kép xung quanh các giá trị (giả sử chúng là giá trị chứ không phải biến).
dallin

3

Bạn có thể tìm thấy đối tượng trong mảng với thư viện Alasql :

var data = [ { name : "bob" , dinner : "pizza" }, { name : "john" , dinner : "sushi" },
     { name : "larry", dinner : "hummus" } ];

var res = alasql('SELECT * FROM ? WHERE dinner="sushi"',[data]);

Hãy thử ví dụ này trong jsFiddle .


3
Tôi không chắc điều này thực sự xứng đáng bị bỏ phiếu xuống. Các truy vấn như Sql trên bộ sưu tập trở nên dễ dàng hơn rất nhiều để lập luận và viết khi các yêu cầu trở nên phức tạp hơn so với một bộ lọc hoặc lệnh gọi giảm đơn lẻ. Alasql là một thư viện khá ấn tượng, nhưng phải thừa nhận là hơi quá mức cần thiết cho ví dụ trên.
TomDotTom,

1
nếu bản thân đối tượng bắt nguồn từ một nguồn SQL, thì câu trả lời này hoàn toàn là thiên tài.
edwardsmarkf

1

Bạn có thể sử dụng một vòng lặp for in đơn giản:

for (prop in Obj){
    if (Obj[prop]['dinner'] === 'sushi'){

        // Do stuff with found object. E.g. put it into an array:
        arrFoo.push(Obj[prop]);
    }
}

Ví dụ fiddle sau đây đặt tất cả các đối tượng chứa dinner:sushivào một mảng:

https://jsfiddle.net/3asvkLn6/1/


1

Đã có rất nhiều câu trả lời hay ở đây, vậy tại sao không có một câu trả lời nữa, hãy sử dụng một thư viện như lodash hoặc gạch dưới :)

obj = {
   1 : { name : 'bob' , dinner : 'pizza' },
   2 : { name : 'john' , dinner : 'sushi' },
   3 : { name : 'larry', dinner : 'hummus' }
}

_.where(obj, {dinner: 'pizza'})
>> [{"name":"bob","dinner":"pizza"}]

0

Tôi đã phải tìm kiếm một cấu trúc sơ đồ trang web lồng nhau cho mục lá đầu tiên đưa ra một đường dẫn nhất định. Tôi đã nghĩ ra mã sau chỉ bằng cách sử dụng .map() .filter().reduce. Trả về mục cuối cùng được tìm thấy khớp với đường dẫn /c.

var sitemap = {
  nodes: [
    {
      items: [{ path: "/a" }, { path: "/b" }]
    },
    {
      items: [{ path: "/c" }, { path: "/d" }]
    },
    {
      items: [{ path: "/c" }, { path: "/d" }]
    }
  ]
};

const item = sitemap.nodes
  .map(n => n.items.filter(i => i.path === "/c"))
  .reduce((last, now) => last.concat(now))
  .reduce((last, now) => now);

Chỉnh sửa 4n4904z07


0

Tôi sẽ cố gắng không phát minh lại bánh xe. Chúng tôi sử dụng quét đối tượng cho tất cả các nhu cầu xử lý dữ liệu của mình. Về mặt khái niệm, nó rất đơn giản, nhưng cho phép tạo ra rất nhiều thứ hay ho. Đây là cách bạn giải quyết câu hỏi cụ thể của mình

Định nghĩa dữ liệu

const data = {
   1 : { name : 'bob' , dinner : 'pizza' },
   2 : { name : 'john' , dinner : 'sushi' },
   3 : { name : 'larry', dinner : 'hummus' }
};

Hợp lý

const objectScan = require('object-scan');

const scanner = (input) => {
  let obj = null;
  objectScan(['*.dinner'], {
    filterFn: (key, value, { parents }) => {
      if (value === 'sushi') {
        obj = parents[0];
      }
    },
    breakFn: () => obj !== null
  })(data);
  return obj;
};

const result = scanner(data);

Đầu ra

// => result
{
  "name": "john",
  "dinner": "sushi"
}

0

Nếu bạn muốn tìm một đối tượng cụ thể thông qua chức năng tìm kiếm, chỉ cần thử một cái gì đó như sau:

    function findArray(value){

        let countLayer = dataLayer.length;
        for(var x = 0 ; x < countLayer ; x++){

            if(dataLayer[x].user){
                let newArr = dataLayer[x].user;
                let data = newArr[value];
                return data;
            }

        }

        return null;

    }

    findArray("id");

Đây là một đối tượng ví dụ:

layerObj = {
    0: { gtm.start :1232542, event: "gtm.js"},
    1: { event: "gtm.dom", gtm.uniqueEventId: 52},
    2: { visitor id: "abcdef2345"},
    3: { user: { id: "29857239", verified: "Null", user_profile: "Personal", billing_subscription: "True", partners_user: "adobe"}
}

Mã sẽ lặp lại và tìm mảng "người dùng" và sẽ tìm kiếm đối tượng Bạn tìm kiếm bên trong.

Vấn đề của tôi là khi chỉ mục mảng thay đổi mỗi lần làm mới cửa sổ và nó nằm trong mảng thứ 3 hoặc thứ hai, nhưng điều đó không quan trọng.

Làm việc như một cái duyên cho tôi!

Trong ví dụ của bạn, nó ngắn hơn một chút:

function findArray(value){

    let countLayer = Object.length;
    for(var x = 0 ; x < countLayer ; x++){

        if(Object[x].dinner === value){
            return Object[x];
        }

    }

    return null;

}

findArray('sushi');
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.