在对象数组中查找匹配的对象?

49
var set = [{"color":"blue"},{"color":"green"},{"color":"red"},{"color":"green"}];

我想要能够进行类似数据库查询的操作,set.find({"color":"green"}),并返回一个包含该属性的对象的数组。


1
已经在https://dev59.com/1nI-5IYBdhLWcg3wf4hD中回答。 - Māris Kiseļovs
1
那个例子不会返回整个对象,对吧? - fancy
1
这与jQuery无关,所以您应该删除该标签。这是一个纯JavaScript问题。 - Domenic
5个回答

89

使用Array#filter,对于这种特殊情况,代码将如下所示

var results = set.filter(function (entry) { return entry.color === "green"; });

Array#filter 在一些旧的浏览器中没有实现,因此请查看链接的文章以获取向后兼容的 shim。或者更好的选择是获得完整的 ES5 shim

对于更一般的情况,只需要扩展这个思路即可:

function findByMatchingProperties(set, properties) {
    return set.filter(function (entry) {
        return Object.keys(properties).every(function (key) {
            return entry[key] === properties[key];
        });
    });
}

var results = findByMatchingProperties(set, { color: "green" });

我再次使用ECMAScript 5的方法Object.keysArray#every,因此需要使用ES5 shim。(没有ES5 shim也可以编写代码,但需要手动循环,编写和阅读起来都不太有趣。)


4
更奇怪的是你还包括了jQuery标签。 - Domenic
这个作为一个方法会是什么样子?set.find({color:"green"}), 基本上是想创建伪数据库功能。 - fancy
@float,您是想将此方法添加到所有数组中,还是仅适用于您的自定义对象,或者其他...?如果是前者,您希望它对整数数组执行什么操作? - Domenic
它可能只是在用户对象上,因此findUser()在用户数组中查找其对象-不需要成为通用方法。 - fancy
欢迎您在如何在JavaScript中使用方法方面提出后续问题,但是为了让您开始,以下是代码示例:var users = { users: [], findUser: function (properties) { return findByMatchingProperties(this.users, properties); } }; - Domenic
我认为在 Angular 2 中使用这个没有任何问题。对吗? - Adrian M.

3
我使用了jQuery的`map`函数,并通过传递搜索关键值来获取选定的索引,因此通过使用该索引,我们将从数组中获取所需的对象。
var mydata = [{ name: "Ram", Id: 1 }, { name: "Shyam", Id: 2 }, { name: "Akhil", Id: 3 }];

searchKey = 2

var mydata = [{ name: "Ram", Id: 1 }, { name: "Shyam", Id: 2 }, { name: "Akhil", Id: 3 }];

searchKey = 2

var selectedData = mydata[mydata.map(function (item) { return item.Id; }).indexOf(searchKey)];

console.log(selectedData)

var selectedData = mydata[mydata.map(function (item) { return item.Id; }).indexOf(searchKey)];

console.log(selectedData)

output
{ name: "Shyam", Id: 2 }

Note: if you want to pass search key as object then
searchKey = { Id: 2 };

mydata[mydata.map(function (item) { return item.Id; }).indexOf(searchKey.Id)];

output
{ name: "Shyam", Id: 2 }

jQuery的map函数正是我所需要的。你的代码片段很棒,也是第一个建议使用map的,所以我给你点了赞。 - Mark

3

使用箭头函数的简洁语法和隐式 return

const results = set.filter(entry => entry.color === "green");

另一个例子是传入搜索变量:

const searchString = 'green'; 
const results = set.filter(entry => entry.color === `${searchString}`);

了解更多有关箭头函数的信息,请访问MDN


1

既然您已经使用了jQuery标签,那么下面是一种使用jQuery的map方法实现的方式:

var results = $.map( set, function(e,i){
  if( e.color === 'green' ) return e; 
});

文档说明需要返回 null 以将元素从数组中删除,但显然这是错误的,正如评论中的 jsFiddle 所示;返回空(即返回 undefined)同样有效。

1
这将返回 [undefined, { color: "green" }, undefined, undefined] - Domenic
1
@Ken Redler,我矫正了。 $ .map的文档说只有在返回null时才会删除该元素,但我想它也认可undefined。不过,我认为通常情况下您可能希望使用$.grep来进行筛选。 - Domenic
1
@Domenic,我确实在文档中看到了关于null的这一点,但据我所知,在某些情况下使用没有返回值的函数的undefined时,它总是能够正常工作。也就是说,如果我没记错的话,完全省略返回语句始终会导致一个空数组。 - Ken Redler
@Ken Redler,是的,我相信你;只是我觉得很糟糕的是,他们的文档没有提到这一点。 - Domenic
1
@Domenic,我同意。我已向jQuery团队提交了一份文档更新建议。 - Ken Redler
你最好使用filter - map是用于将类型A的列表转换为具有相同元素数量的类型B的列表。我并不是说它不能工作,但它使用了错误的工具来完成任务。 - Dan G

0

我采用了一种不同的方法,我发现这种方法更容易。

function isObjEqual(a, b) {
    const x = JSON.stringify(a);
    const y = JSON.stringify(b);
  
    return x === y;
  }

// Example 1
const set = [{"color":"blue"},{"color":"green"},{"color":"red"},{"color":"green"}];
const findObj1 = {"color":"green"};
const arr1 = set.filter((objInArr) => isObjEqual(objInArr, findObj1));
console.log(arr1) // [ { color: 'green' }, { color: 'green' } ]

  // Example 2
const list = [{
    "label": "Option 2",
    "value": "option2"
  },
  {
    "label": "Option 3",
    "value": "option3"
  },
  {
    "label": "Option 2",
    "value": "option2"
  }
];

const findObj2 = {
  "label": "Option 2",
  "value": "option2"
}

const newList = list.filter((objInArr) => isObjEqual(objInArr, findObj2));
console.log(newList) //[ { label: 'Option 2', value: 'option2' }, { label: 'Option 2', value: 'option2' } ]


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