我有一个像
vendors = [{
Name: 'Magenic',
ID: 'ABC'
},
{
Name: 'Microsoft',
ID: 'DEF'
} // and so on...
];
如何检查此数组以查看“Magenic”是否存在?我不想循环,除非我必须这样做。我正在处理可能有几千条记录。
filter
或 some
虽然很漂亮,但不如使用显式循环好。 (由于必须为数组中的每个元素执行 lambda,它们会导致性能下降。)
无需重新发明 wheel 循环,至少无需明确(使用 arrow functions、modern browsers only):
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.filter(function(e) { return e.Name === 'Magenic'; }).length > 0) {
/* vendors contains the element we're looking for */
}
2018 年编辑:这个答案来自 2011 年,当时浏览器还没有广泛支持数组过滤方法和箭头函数。看看CAFxX's answer。
没有“神奇”的方法可以在没有循环的情况下检查数组中的某些内容。即使您使用某些函数,该函数本身也会使用循环。您可以做的是在您找到所需内容后立即跳出循环,以最大限度地减少计算时间。
var found = false;
for(var i = 0; i < vendors.length; i++) {
if (vendors[i].Name == 'Magenic') {
found = true;
break;
}
}
'Magenic'
位于对象中的其他位置,很容易导致误报
不需要循环。想到的三种方法:
Array.prototype.some()
这是您问题的最准确答案,即“检查是否存在”,暗示布尔结果。如果有任何 'Magenic' 对象,这将是 true,否则为 false:
let hasMagenicVendor = vendors.some( vendor => vendor['Name'] === 'Magenic' )
Array.prototype.filter()
这将返回一个包含所有 'Magenic' 对象的数组,即使只有一个(将返回一个单元素数组):
let magenicVendors = vendors.filter( vendor => vendor['Name'] === 'Magenic' )
如果您尝试将其强制为布尔值,它将不起作用,因为空数组(没有“Magenic”对象)仍然是真实的。因此,只需在条件中使用 magenicVendors.length
。
Array.prototype.find()
这将返回第一个 'Magenic' 对象(如果没有,则返回 undefined
):
let magenicVendor = vendors.find( vendor => vendor['Name'] === 'Magenic' );
这将强制转换为布尔值 OK(任何对象都是真实的,undefined
是虚假的)。
注意:我使用 vendor["Name"] 而不是 vendor.Name 因为属性名称的奇怪大小写。
注意 2:在检查名称时,没有理由使用松散相等 (==) 而不是严格相等 (===)。
接受的答案仍然有效,但现在我们有一个 ECMAScript 6 本机方法 [Array.find][1]
和 [Array.some][2]
来实现相同的效果。
数组.some
如果您只想确定一个元素是否存在,即您需要一个true/false
确定,请使用 some
。
引用 MDN:
some() 方法测试数组中的至少一个元素是否通过了提供的函数实现的测试。如果在数组中找到所提供函数为其返回 true 的元素,则返回 true;否则返回false。它不会修改数组。
Array.find
如果要从数组中获取匹配的对象,请使用 find,否则返回 undefined
。
引用 MDN:
find() 方法返回提供的数组中满足提供的测试功能的第一个元素的值。如果没有值满足测试函数,则返回 undefined。
var arr = [];
var item1 = {
id: 21,
label: 'Banana',
};
var item2 = {
id: 22,
label: 'Apple',
};
arr.push(item1, item2);
/* note : data is the actual object that matched search criteria
or 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 link IE 有一个 polyfill provided by mozilla
return ele.id == '2'
可能会更短,但 +1 是一个好的 ES6 解决方案。
push if <0 || splice(index, 1)
这是我稍微更新的代码:const index = this.selected.indexOf(this.selected.find(s => s.id == passedObj.id))
return ele.id === 21;
;它是一个数字,而不是一个字符串。
这是我的做法
const found = vendors.some(item => item.Name === 'Magenic');
array.some()
方法检查数组中是否至少有一个值与条件匹配并返回布尔值。从这里开始,您可以使用:
if (found) {
// do something
} else {
// do something else
}
除非你想像这样重组它:
vendors = {
Magenic: {
Name: 'Magenic',
ID: 'ABC'
},
Microsoft: {
Name: 'Microsoft',
ID: 'DEF'
} and so on...
};
你可以做的if(vendors.Magnetic)
你将不得不循环
根据 ECMAScript 6 规范,您可以使用 findIndex
。
const magenicIndex = vendors.findIndex(vendor => vendor.Name === 'Magenic');
magenicIndex
将保存 0
(它是数组中的索引)或 -1
(如果未找到)。
可能为时已晚,但 javascript 数组有两个方法 some
和 every
方法返回一个布尔值,可以帮助您实现这一点。
我认为 some
最适合您打算实现的目标。
vendors.some( vendor => vendor['Name'] !== 'Magenic' )
有些验证数组中的任何对象都满足给定条件。
vendors.every( vendor => vendor['Name'] !== 'Magenic' )
Every 验证数组中的所有对象都满足给定条件。
array.some
方法!
正如 OP 已询问密钥是否存在的问题。
使用 ES6 reduce 函数返回布尔值的更优雅的解决方案是
const magenicVendorExists = vendors.reduce((accumulator, vendor) => (accumulator||vendor.Name === "Magenic"), false);
注意:reduce的初始参数是一个false
,如果数组有key则返回true。
希望它有助于更好和更清洁的代码实现
reduce
的第一个参数是累加器,而不是 vendor
对象。这会在每个循环中检查 false.Name === "Magenic"
并返回 false
你不能不真正地观察对象。
你可能应该稍微改变你的结构,比如
vendors = {
Magenic: 'ABC',
Microsoft: 'DEF'
};
然后你可以像查找哈希一样使用它。
vendors['Microsoft']; // 'DEF'
vendors['Apple']; // undefined
测试数组元素:
JS 提供数组函数,让您相对容易地实现这一点。它们是:
Array.prototype.filter:接受一个回调函数,它是一个测试,然后用is回调迭代数组,并根据这个回调过滤。返回一个新的过滤数组。 Array.prototype.some:接受一个作为测试的回调函数,然后使用回调函数迭代数组,如果任何元素通过测试,则返回布尔值true。否则返回 false
具体细节最好通过一个例子来解释:
例子:
vendor = [ { Name: 'Magenic', ID: 'ABC' }, { Name: 'Microsoft', ID: 'DEF' } //依此类推数组... ]; // filter 返回一个新数组,我们立即检查这个新创建的数组的长度 // 是否大于零 if (vendors.filter(company => company.Name === 'Magenic').length ) { console. log('我包含 Magenic'); } // some 会是一个比过滤更好的选择,因为它直接返回一个布尔值 if (vendors.some(company => company.Name === 'Magenic')) { console.log('I also contains Magenic'); }
浏览器支持:
这 2 个函数是 ES6
函数,并非所有浏览器都支持它们。为了克服这个问题,您可以使用 polyfill。这是 Array.prototype.some
的 polyfill(来自 MDN):
if (!Array.prototype.some) { Array.prototype.some = function(fun, thisArg) { 'use strict'; if (this == null) { throw new TypeError('Array.prototype.some call on null or undefined'); } if (typeof fun !== 'function') { throw new TypeError(); } var t = 对象(这个); 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; } } 返回假; }; }
const check = vendors.find((item)=>item.Name==='Magenic')
console.log(check)
试试这个代码。
如果项目或元素存在,则输出将显示该元素。如果它不存在,则输出将是“未定义”。
2021 年解决方案*
Lodash .some
(docs) 是一个干净的解决方案,如果您使用 _matchesProperty
(docs) 速记:
_.some(VENDORS, ['Name', 'Magenic'])
解释
这将遍历 VENDORS
数组以查找具有 Name
键的元素对象,该键具有字符串 'Magenic'
的值。一旦找到这个元素,它就会返回 true
并停止迭代。如果遍历整个 Array 后没有找到该元素,则返回 false
。
代码片段
const VENDORS = [{ 名称:'Magenic',ID:'ABC'},{ 名称:'Microsoft',ID:'DEF'}]; console.log(_.some(VENDORS, ['Name', 'Magenic'])); // true
*
请注意,这使用流行的 lodash
库来实现最简单/最短的解决方案。对于那些感兴趣的人,我提供了它作为现有 vanilla JS 解决方案的替代方案。
你必须循环,没有办法绕过它。
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 会比直接循环更快,但当事情变得更复杂时,它肯定会更灵活。
如果我错了,请纠正我.. 我可以使用这样的 forEach
方法,
var found=false;
vendors.forEach(function(item){
if(item.name === "name"){
found=true;
}
});
现在我已经习惯了,因为它简单且不言自明。谢谢你。
我解决这个问题的方法是使用 ES6 并创建一个为我们进行检查的函数。此函数的好处是它可以在整个项目中重复使用,以检查给定 key
和 value
的任何对象数组进行检查。
说够了,让我们看看代码
大批
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
函数 map
、filter
、find
和类似函数比简单循环慢。对我来说,它们的可读性也比简单循环低,而且更难调试。使用它们看起来像是一种非理性的仪式。
最好有这样的东西:
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');
arrayContainsObject
应该是您编写一次就忘记的库方法。如果您愿意,您实际上可以使用数组函数编写它。从可读性的角度来看,没有什么比 arrayHelper.arrayContainsObject
更好的了。
findIndexOfObject
。所以,最好同时拥有它们。
迄今为止最简单的方法:
if (vendors.findIndex(item => item.Name == "Magenic") == -1) {
//not found item
} else {
//found item
}
如果您使用的是 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);
}
你可以使用 lodash。如果 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);
希望我的回答有帮助。
这里的许多答案都很好而且很容易。但是,如果您的对象数组具有一组固定的值,那么您可以使用以下技巧:
映射对象中的所有名称。
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.
}
现在这个dirtyObj 可以在没有任何循环的情况下一次又一次地使用。
if(dirtyObj[vendor.Name]){
console.log("Hey! I am available.");
}
为了将一个对象与另一个对象进行比较,我结合了 for in 循环(用于循环对象)和 some()。您不必担心数组超出范围等,这样可以节省一些代码。可以找到关于 .some 的文档here
var productList = [{id: 'text3'}, {id: 'text2'}, {id: 'text4', product: 'Shampoo'}]; // Example of selected products
var 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 here
objectsFound.push(currentId);
}
}
console.log(objectsFound);
我将一个对象与另一个对象进行比较的另一种方法是使用带有 Object.keys().length 的嵌套 for 循环来获取数组中对象的数量。下面的代码:
var productList = [{id: 'text3'}, {id: 'text2'}, {id: 'text4', product: 'Shampoo'}]; // Example of selected products
var 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');
}
}
或者,您可以这样做:
const find = (key, needle) => return !!~vendors.findIndex(v => (v[key] === needle));
var without2 = (arr, args) => arr.filter(v => v.id !== args.id);
示例:
without2([{id:1},{id:1},{id:2}],{id:2})
结果:没有2([{id:1},{id:1},{id:2}],{id:2})
你可以试试这个它对我的工作。
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 } ]
const a = [{one:2},{two:2},{two:4}]
const b = a.filter(val => "two" in val).length;
if (b) {
...
}
我宁愿使用正则表达式。
如果你的代码如下,
vendors = [
{
Name: 'Magenic',
ID: 'ABC'
},
{
Name: 'Microsoft',
ID: 'DEF'
}
];
我会推荐
/"Name":"Magenic"/.test(JSON.stringify(vendors))
"Magenic"
匹配。正则表达式答案的误报:[ { "Not the property you’re looking for": { "Name": "Magenic" } } ]
或 [ { 'Not the property you’re looking for"Name': "Magenic" } ]
;潜在的假阴性(特别是如果问题要求 own 属性):[ Object.create({ Name: "Magenic" }) ]
。
some
更好 ?name === "Magenic"
的对象,some
就会短路。使用filter
,它将检查每个项目直到数组末尾并创建一个符合条件的新数组项目,然后检查length
.some
的评论。现在是 2019 年,使用.some
并使用 Polyfills 来支持糟糕的浏览器并继续你的生活...... polyfill.io/v3/url-builder。我唯一能看到的是,如果你不能支持箭头函数,那么它就像我提到的 Polyfill 一样简单:arr.some(function(i) { return i.Name === "Magenic" })