如何在JavaScript的对象数组中查找值?

96
我有一个对象数组:
Object = {
   1 : { name : bob , dinner : pizza },
   2 : { name : john , dinner : sushi },
   3 : { name : larry, dinner : hummus }
}

我希望能够搜索对象/数组中键为“dinner”的元素,并查看是否匹配“sushi”。

我知道jQuery有$.inArray,但它似乎不适用于对象数组。或者我错了。indexOf也似乎只适用于一个数组层级。

是否没有函数或现有代码可以实现这一功能?


这个问题以前已被问过。你必须编写自己的函数或使用其他库。 - Felix Kling
1
请注意,在Javascript中,Object是保留字,Object是对象对象,即所有对象的母体。 - ase
1
他们没有解决我的“在多维数组中查找值”的问题。 - Martin Schneider
10个回答

225
如果您有一个数组如下:
var people = [
  { "name": "bob", "dinner": "pizza" },
  { "name": "john", "dinner": "sushi" },
  { "name": "larry", "dinner": "hummus" }
];

您可以使用数组对象的filter方法:

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

在较新的JavaScript实现中,您可以使用函数表达式:

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

您可以使用map来搜索拥有"dinner": "sushi"的人。

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

或者一个reduce

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

我相信你能将此推广到任意键和值!


7
请记住,这些解决方案是ECMAScript 5的一部分,不支持IE8。http://kangax.github.com/es5-compat-table/尽管我更喜欢@adamse的答案,但alex的答案更适用于“旧的烂浏览器”。不确定性能如何。 - EasyCo
@SalmanA - 问题和解决方案都没有涉及到jQuery。使用的是JavaScript的filter()方法,而不是jQuery特有的$.filter()方法 - http://www.tutorialspoint.com/javascript/array_filter.htm - J.G.Sebring
正如EasyCo所提到的,IE8不支持filter函数。但是,只需在脚本开头添加一个小函数,就可以将其添加到Array原型中,并在任何浏览器中使用。这在filter文档中有详细说明。它提供了ECMA-262中指定的确切函数,因此它们完全相同。 - dallin
1
我刚刚添加了一个答案,其中使用了jQuery的grep方法。将其整合到你的答案中可能是有意义的,因为它与你所做的相同,但需要依赖于jQuery且兼容性不佳的浏览器。 - Zach Lysobey
我为什么总是得到一个关于返回变量的引用错误?我尝试了前两个答案返回“x”,但它一直显示未定义... - Evan Lalo
@EvanLalo 你应该关于此提出一个新问题。 - ase

18
jQuery有一个内置方法jQuery.grep,与来自@adamse's Answer的ES5 filter函数类似,并且应该可以在旧版本浏览器上正常工作。
使用adamse的示例:
var peoples = [
  { "name": "bob", "dinner": "pizza" },
  { "name": "john", "dinner": "sushi" },
  { "name": "larry", "dinner": "hummus" }
];

你可以做以下事情

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;       

}

只要-1不是一个有效的键。

jsFiddle.


几乎点赞了这个帖子,但是没有解释。 - mickmackusa

10

如果您要频繁执行此搜索,请考虑更改对象的格式,使晚餐实际上成为一个键。这有点像在数据库表中分配主聚集键。例如:

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

现在您可以这样轻松地访问它:Object ['sushi'] ['name']

或者,如果对象确实如此简单(对象中只有“name”),则可以将其更改为:

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

然后像这样访问它:Object['sushi']

显然,并不总是可能或者有利于重构你的数据对象,但关键是,有时候最好的解决方案是考虑你的数据对象是否被最佳结构化。创建这样的一个键可以更快地执行和创造更干净的代码。


1
非常感谢您的回答,但我发现语法有问题: 我的代码只能像这样工作: obj = { "pizza" : { "name" : "bob" }, "sushi" : { "name" : "john" } } alert (obj['pizza']['name']); 但还是非常感谢!我找到了我要寻找的东西!) - aleXela
@alexela 谢谢你,alexela!我已经根据你的敏锐观察更新了我的答案!我只是复制了原帖中的示例,并忽略了添加引号,但你是对的——除非在值周围加上引号(假设它们是值而不是变量),否则它将无法正常工作。 - dallin

3
你可以使用Alasql库在数组中查找对象:
var data = [ { name : "bob" , dinner : "pizza" }, { name : "john" , dinner : "sushi" },
     { name : "larry", dinner : "hummus" } ];

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

请在 jsFiddle 中尝试此示例 (链接)


3
我不确定这个回答真的应该被踩。当需求比单纯的筛选或归约更为复杂时,对集合进行类似于SQL的查询会变得更加易于理解和编写。Alasql是一个相当令人印象深刻的库,但承认它对于上述示例来说可能有点过于复杂。 - TomDotTom
1
如果对象本身来自SQL源,则这个答案非常聪明。 - edwardsmarkf

1

我需要在一个嵌套的网站地图结构中搜索第一个与给定路径匹配的叶子项。我使用了以下代码,仅使用.map() .filter().reduce()。返回与路径/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);

Edit 4n4904z07


1

这里已经有很多好的答案了,为什么不再加一个:使用像lodash或underscore这样的库 :)

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

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

1
您可以使用简单的for-in循环:

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]);
    }
}

以下的fiddle示例将包含 dinner:sushi 的所有对象放入一个数组中:

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


0

我们在大部分数据处理中使用object-scan。它的概念非常简单,但可以实现很多酷炫的功能。以下是解决你问题的方法:

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

const findDinner = (dinner, data) => objectScan(['*'], {
  abort: true,
  rtn: 'value',
  filterFn: ({ value }) => value.dinner === dinner
})(data);

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

console.log(findDinner('sushi', data));
// => { name: 'john', dinner: 'sushi' }
.as-console-wrapper {max-height: 100% !important; top: 0}
<script src="https://bundle.run/object-scan@13.8.0"></script>

声明:本人是object-scan的作者。


0
如果您想通过搜索功能查找特定对象,只需尝试类似以下代码:
    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");

这是一个示例对象:

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"}
}

代码将迭代并查找“用户”数组,然后在其中搜索您要查找的对象。

我的问题是当数组索引在每个窗口刷新时更改,并且它可能在第三个或第二个数组中,但这并不重要。

对我来说非常有效!

在您的示例中,它有点短:

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');

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接