如何确定Javascript数组是否包含具有等于给定值的属性的对象?

我有一个数组

vendors = [{Name: 'Magenic',ID: 'ABC'},{Name: 'Microsoft',ID: 'DEF'} // and so on...];

我如何检查此数组以查看“Mag的”是否存在?除非迫不得已,否则我不想循环。我正在处理可能有几千条记录。

1514600 次浏览

除非你想把它改成这样:

vendors = {Magenic: {Name: 'Magenic',ID: 'ABC'},Microsoft: {Name: 'Microsoft',ID: 'DEF'} and so on...};

你能做的if(vendors.Magnetic)

你将不得不循环

2018编辑:这个答案来自2011年,在浏览器广泛支持数组过滤方法和箭头函数之前。看看CAFxX的回答

没有“神奇”的方法可以在没有循环的情况下检查数组中的某些内容。即使你使用某个函数,函数本身也会使用循环。你能做的就是在找到你要找的东西时立即打破循环,以最小化计算时间。

var found = false;for(var i = 0; i < vendors.length; i++) {if (vendors[i].Name == 'Magenic') {found = true;break;}}

你不能不看对象真的。

你应该稍微改变一下你的结构,比如

vendors = {Magenic:   'ABC',Microsoft: 'DEF'};

然后你可以像使用lookup-hash一样使用它。

vendors['Microsoft']; // 'DEF'vendors['Apple']; // undefined

你必须循环,没有办法绕过它。

function seekVendor(vendors, name) {for (var i=0, l=vendors.length; i<l; i++) {if (typeof vendors[i] == "object" && vendors[i].Name === name) {return vendors[i];}}}

当然,您可以使用像linq.js这样的库来使其更令人愉快:

Enumerable.From(vendors).Where("$.Name == 'Magenic'").First();

(见jsFiddle演示)

我怀疑linq.js会比直接循环更快,但当事情变得更复杂时,它肯定会更灵活。

不需要重新发明车轮循环,至少不是显式的(使用箭头函数现代浏览器只):

if (vendors.filter(e => e.Name === 'Magenic').length > 0) {/* vendors contains the element we're looking for */}

或者,更好的,使用一些,因为它允许浏览器在找到匹配的元素后立即停止,所以它会更快:

if (vendors.some(e => e.Name === 'Magenic')) {/* vendors contains the element we're looking for */}

或等效(在这种情况下)找到

if (vendors.find(e => e.Name === 'Magenic')) {/* same result as above, but a different function return type */}

你甚至可以使用查找索引来获取该元素的位置:

const i = vendors.findIndex(e => e.Name === 'Magenic');if (i > -1) {/* vendors contains the element we're looking for, at index "i" */}

如果你需要与糟糕的浏览器兼容,那么你最好的选择是:

if (vendors.filter(function(e) { return e.Name === 'Magenic'; }).length > 0) {/* vendors contains the element we're looking for */}

如果您使用的是jQuery,您可以利用grep创建包含所有匹配对象的数组:

var results = $.grep(vendors, function (e) {return e.Name == "Magenic";});

然后使用结果数组:

for (var i=0, l=results.length; i<l; i++) {console.log(results[i].ID);}

接受的答案仍然有效,但现在我们有一个ECMAScript 6本机方法[Array.find][1][Array.some][2]来实现相同的效果。

Array.some

使用some如果您只想确定元素是否存在,即您需要true/false确定。

引用MDN:

一些()方法测试数组中是否至少有一个元素通过了提供函数实现的测试。如果在数组中找到提供函数返回true的元素,则返回true;否则返回false。它不修改数组。

Array.find

如果您想从数组中获取匹配的对象,请使用查找,否则返回undefined

引用MDN:

find()方法返回提供的数组中满足提供的测试函数的第一个元素的值。如果没有值满足测试函数,则返回未定义。

var arr = [{id: 21,label: 'Banana',},{id: 22,label: 'Apple',}]
/* note : data is the actual object that matched search criteriaor undefined if nothing matched */
var data = arr.find(function(ele) {return ele.id === 21;});
if (data) {console.log('found');console.log(data); // This is entire object i.e. `item` not boolean}

/* note : doesExist is a boolean thats true or false depending on of whether the data was found or not */var doesExist = arr.some(function(ele) {return ele.id === 21;});

看看我的jsfiddle链接有一个IE由mozilla提供的多边形填充

我宁愿选择regex。

如果您的代码如下,

vendors = [{Name: 'Magenic',ID: 'ABC'},{Name: 'Microsoft',ID: 'DEF'}];

我建议

/"Name":"Magenic"/.test(JSON.stringify(vendors))

不需要循环。想到的三种方法:

Array.prototype.some()

这是对您问题的最准确答案,即“检查是否存在”,暗示一个布尔结果。如果有任何“Mag的”对象,这将是true,否则为false:

let hasMagenicVendor = vendors.some( vendor => vendor['Name'] === 'Magenic' )

Array.prototype.filter()

这将返回一个包含所有'Magene'对象的数组,即使只有一个(将返回一个单元素数组):

let magenicVendors = vendors.filter( vendor => vendor['Name'] === 'Magenic' )

如果您尝试将其强制转换为布尔值,它将不起作用,因为空数组(没有'Mag的'对象)仍然是true。所以只需在条件中使用magenicVendors.length

Array.prototype.find()

这将返回第一个“Mag的”对象(如果没有,则返回undefined):

let magenicVendor = vendors.find( vendor => vendor['Name'] === 'Magenic' );

这将强制转换为布尔值ok(任何对象都是truthy,undefined是false sy)。


注意:由于属性名称的奇怪大小写,我使用的是供应商["Name"]而不是供应商. Name。

注意2:检查名称时,没有理由使用松散相等(==)而不是严格相等 (===) 。

根据ECMAScript 6规范,您可以使用#0

const magenicIndex = vendors.findIndex(vendor => vendor.Name === 'Magenic');

magenicIndex将保存0(数组中的索引)或-1(如果未找到)。

如果我说错了请纠正我。我可以用这样的forEach方法,

var found=false;vendors.forEach(function(item){if(item.name === "name"){found=true;
}});

现在我已经习惯了,因为它的简单和不言自明的词。谢谢你!

你可以使用豆沙。如果对你的应用程序来说,Lodash库太重了,考虑分块掉不需要的函数。

let newArray = filter(_this.props.ArrayOne, function(item) {return find(_this.props.ArrayTwo, {"speciesId": item.speciesId});});

这只是一种方法。另一种方法可以是:

var newArray=  [];_.filter(ArrayOne, function(item) {return AllSpecies.forEach(function(cItem){if (cItem.speciesId == item.speciesId){newArray.push(item);}})});

console.log(arr);

上面的示例也可以是重写而不使用任何库,例如:

var newArray=  [];ArrayOne.filter(function(item) {return ArrayTwo.forEach(function(cItem){if (cItem.speciesId == item.speciesId){newArray.push(item);}})});console.log(arr);

希望我的回答有帮助。

或者,您可以这样做:

const find = (key, needle) => return !!~vendors.findIndex(v => (v[key] === needle));

var不了2=(arr, args)=>arr.filter(v=>v.id!==args.id);示例:

不带2([{id: 1},{id: 1},{id: 2}],{id: 2})

结果:不含2([{id: 1},{id: 1},{id: 2}],{id: 2})

这里的许多答案都很好并且非常简单。但是如果您的对象数组具有一组固定的值,那么您可以使用以下技巧:

映射对象中的所有名称。

vendors = [{Name: 'Magenic',ID: 'ABC'},{Name: 'Microsoft',ID: 'DEF'}];
var dirtyObj = {}for(var count=0;count<vendors.length;count++){dirtyObj[vendors[count].Name] = true //or assign which gives you true.}

现在,您可以一次又一次地使用这个脏Obj,而无需任何循环。

if(dirtyObj[vendor.Name]){console.log("Hey! I am available.");}

因为OP问了问题如果密钥存在或不存在

一个更优雅的解决方案,将使用ES6 Reduce函数返回布尔值

const magenicVendorExists =  vendors.reduce((accumulator, vendor) => (accumulator||vendor.Name === "Magenic"), false);

备注: duce的初始参数是false,如果数组有键,它将返回true。

希望它有助于更好、更清晰的代码实现

这是我做的方法

const found = vendors.some(item => item.Name === 'Magenic');

array.some()方法检查数组中是否至少有一个值与条件匹配并返回布尔值。从这里开始,您可以使用:

if (found) {// do something} else {// do something else}

为了将一个对象与另一个对象进行比较,我结合了一个for in loop(用于循环遍历对象)和一些()。您不必担心数组越界等问题,这样可以节省一些代码。可以在.一些上找到文档这里

var productList = [{id: 'text3'}, {id: 'text2'}, {id: 'text4', product: 'Shampoo'}]; // Example of selected productsvar theDatabaseList = [{id: 'text1'}, {id: 'text2'},{id: 'text3'},{id:'text4', product: 'shampoo'}];var  objectsFound = [];
for(let objectNumber in productList){var currentId = productList[objectNumber].id;if (theDatabaseList.some(obj => obj.id === currentId)) {// Do what you need to do with the matching value hereobjectsFound.push(currentId);}}console.log(objectsFound);

我比较一个对象与另一个对象的另一种方法是使用带有Object.keys(). long的嵌套for循环来获取数组中对象的数量。代码如下:

var productList = [{id: 'text3'}, {id: 'text2'}, {id: 'text4', product: 'Shampoo'}]; // Example of selected productsvar theDatabaseList = [{id: 'text1'}, {id: 'text2'},{id: 'text3'},{id:'text4', product: 'shampoo'}];var objectsFound = [];
for(var i = 0; i < Object.keys(productList).length; i++){for(var j = 0; j < Object.keys(theDatabaseList).length; j++){if(productList[i].id === theDatabaseList[j].id){objectsFound.push(productList[i].id);}}}console.log(objectsFound);

要回答您的确切问题,如果只是在对象中搜索值,您可以使用单个for in循环。

var vendors = [{Name: 'Magenic',ID: 'ABC'},{Name: 'Microsoft',ID: 'DEF'}];
for(var ojectNumbers in vendors){if(vendors[ojectNumbers].Name === 'Magenic'){console.log('object contains Magenic');}}

我解决这个问题的方法是使用ES6并创建一个为我们进行检查的函数。这个函数的好处是它可以在整个项目中重用,以检查给定keyvalue要检查的任何对象数组。

够了让我们看看密码

数组

const ceos = [{name: "Jeff Bezos",company: "Amazon"},{name: "Mark Zuckerberg",company: "Facebook"},{name: "Tim Cook",company: "Apple"}];

函数

const arrayIncludesInObj = (arr, key, valueToCheck) => {return arr.some(value => value[key] === valueToCheck);}

呼叫/使用

const found = arrayIncludesInObj(ceos, "name", "Tim Cook"); // true
const found = arrayIncludesInObj(ceos, "name", "Tim Bezos"); // false

你可以试试这对我的工作。

const _ = require('lodash');
var arr = [{name: 'Jack',id: 1},{name: 'Gabriel',id: 2},{name: 'John',id: 3}]
function findValue(arr,value) {return _.filter(arr, function (object) {return object['name'].toLowerCase().indexOf(value.toLowerCase()) >= 0;});}
console.log(findValue(arr,'jack'))//[ { name: 'Jack', id: 1 } ]

数组元素测试:

JS提供数组函数,让您可以相对轻松地实现这一点。它们如下:

  1. Array.prototype.filter:接受一个回调函数,它是一个测试,然后用is回调迭代数组,并根据这个回调进行过滤。返回一个新的过滤数组。
  2. Array.prototype.some:接受一个回调函数,它是一个测试,然后用is回调和如果任何元素通过测试,返回布尔值true。否则返回false迭代数组

具体细节最好通过一个例子来解释:

示例:

vendors = [{Name: 'Magenic',ID: 'ABC'},{Name: 'Microsoft',ID: 'DEF'} //and so on goes array...];
// filter returns a new array, we instantly check if the length// is longer than zero of this newly created arrayif (vendors.filter(company => company.Name === 'Magenic').length ) {console.log('I contain Magenic');}
// some would be a better option then filter since it directly returns a booleanif (vendors.some(company => company.Name === 'Magenic')) {console.log('I also contain Magenic');}

浏览器支持:

这2个函数是ES6函数,并非所有浏览器都支持它们。为了克服这个问题,你可以使用Poly填充。这是Array.prototype.some的Poly填充(来自MDN):

if (!Array.prototype.some) {Array.prototype.some = function(fun, thisArg) {'use strict';
if (this == null) {throw new TypeError('Array.prototype.some called on null or undefined');}
if (typeof fun !== 'function') {throw new TypeError();}
var t = Object(this);var len = t.length >>> 0;
for (var i = 0; i < len; i++) {if (i in t && fun.call(thisArg, t[i], i, t)) {return true;}}
return false;};}

可能为时已晚,但javascript数组有两个方法someevery方法返回布尔值,可以帮助您实现这一目标。

我认为some最适合你打算实现的目标。

vendors.some( vendor => vendor['Name'] !== 'Magenic' )

一些验证数组中的任何对象是否满足给定条件。

vendors.every( vendor => vendor['Name'] !== 'Magenic' )

每个都验证数组中的所有对象是否满足给定条件。

const a = [{one:2},{two:2},{two:4}]const b = a.filter(val => "two" in val).length;if (b) {...}

2021解决方案*

Lodash.some文档)是一个干净的解决方案,如果您使用_matchesProperty文档)速记:

_.some(VENDORS, ['Name', 'Magenic'])

补充说明

这将遍历VENDORS数组,查找Name键的值为String'Magenic'的元素Object。找到此元素后,它返回true并停止迭代。如果在查看整个数组后没有找到该元素,它将返回false

代码段

const VENDORS = [{ Name: 'Magenic', ID: 'ABC' }, { Name: 'Microsoft', ID: 'DEF' }];
console.log(_.some(VENDORS, ['Name', 'Magenic'])); // true
<script src="https://cdn.jsdelivr.net/npm/lodash@4.17.20/lodash.min.js"></script>

* Note that this uses the popular lodash library to achieve the simplest/shortest possible solution. I'm offering this as an alternative to the existing vanilla JS solutions, for those who are interested.

const check = vendors.find((item)=>item.Name==='Magenic')
console.log(check)

试试这个代码。

如果项目或元素存在,则输出将显示该元素。如果不存在,则输出将为“未定义”。

函数mapfilterfind和类似的函数比简单循环慢。对我来说,它们的可读性也不如简单的循环,更难调试。使用它们看起来像是一种非理性的仪式。

最好有这样的东西:

 arrayHelper = {arrayContainsObject: function (array, object, key){for (let i = 0; i < array.length; i++){if (object[key] === array[i][key]){return true;}}return false;}     
};

并将其与给定的OP示例一起使用:

    vendors = [{Name: 'Magenic',ID: 'ABC'},{Name: 'Microsoft',ID: 'DEF'}];
let abcObject = {ID: 'ABC', Name: 'Magenic'};
let isContainObject = arrayHelper.arrayContainsObject(vendors, abcObject, 'ID');

迄今为止最简单的方法:

if (vendors.findIndex(item => item.Name == "Magenic") == -1) {//not found item} else {//found item}