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

2020/09/21 23:21 · javascript ·  · 0评论

我有一个像

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

如何检查此阵列以查看Magenic是否存在?我不想循环,除非必须这样做。我正在处理几千条记录。


更新

由于这是一个受欢迎的帖子,我想分享一些新发现。看来@CAFxX已经分享了!我应该更经常阅读这些内容。我遇到了https://benfrain.com/understanding-native-javascript-array-methods/

vendors.filter(function(vendor){ return vendor.Name === "Magenic" })

借助ECMAScript 2015,使用新的箭头功能甚至更加简单:

vendors.filter(vendor => vendor.Name === "Magenic")

2018 edit:这个答案来自2011,当时浏览器没有广泛支持数组过滤方法和箭头功能。看一下CAFxX的答案

没有“魔术”的方法来检查没有循环的数组中的某些内容。即使使用某些函数,该函数本身也会使用循环。您所能做的就是在找到要查找的内容后立即打破循环,以最大程度地减少计算时间。

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

无需重新发明 循环,至少没有明确地循环(仅使用箭头功能仅适用于现代浏览器):

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 */
}

无需循环。我想到了三种方法:

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

这强制为布尔值(任何对象都是真实的,undefined是虚假的)。


注意:由于属性名称的大小写很怪异,所以我使用vendor [“ Name”]而不是vendor.Name。

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

可接受的答案仍然有效,但是现在我们有了ECMAScript 6本机方法[Array.find][1]来达到相同的效果。

报价MDN:

find()方法返回满足提供的测试功能的数组中第一个元素的值。否则,返回未定义。

var arr = []; 
var item = {
  id: '21',
  step: 'step2',
  label: 'Banana',
  price: '19$'
};

arr.push(item);
/* 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
}

查看我的jsfiddle链接。mozilla 提供了 IE的polyfill

这是我会做的方式

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找不到它。

由于OP询问了密钥是否存在的问题

可以使用ES6 reduce函数返回布尔值的更优雅的解决方案是

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

注意: reduce的初始参数是a false,如果数组具有键,它将返回true。

希望它有助于更​​好,更干净地执行代码

您不能不真正地调查对象。

您可能应该稍微改变一下结构,例如

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

然后,您可以像使用哈希表一样使用它。

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

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

我认为some最适合您要实现的目标。

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

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

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

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

测试数组元素:

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 array
if (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 boolean
if (vendors.some(company => company.Name === 'Magenic')) {
  console.log('I also contain Magenic');
}

浏览器支持:

这两个功能是ES6功能,并非所有浏览器都支持它们。为了克服这个问题,您可以使用polyfill。这是Array.prototype.some(来自MDN)的polyfill

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

您必须循环,无法解决。

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会比直接循环更快,但是当事情变得更复杂时,它肯定会更灵活。

如果您使用的是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);
}

纠正我,如果我错了..我本可以使用这样的forEach方法,

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

   }
});

如今我已经习惯了,因为它简单易懂。谢谢。

您可以为我尝试它的工作。

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) {
   ...
}

您可以使用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循环(用于循环遍历对象)和some()进行了组合。您不必担心数组越界越好,这样可以节省一些代码。有关.some的文档可以在这里找到

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 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 VENDORS = [{ Name: 'Magenic', ID: 'ABC' }, { Name: 'Microsoft', ID: 'DEF' }];

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

或者,您可以执行以下操作:

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

解决这个问题的方法是使用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) => {
  let found = false;

  arr.some(value => {
    if (value[key] === valueToCheck) {
      found = true;
      return true; // this will break the loop once found
    }
  });

  return found;
}

通话/使用

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

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

我宁愿使用正则表达式。

如果您的代码如下,

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

我会推荐

/"Name":"Magenic"/.test(JSON.stringify(vendors))
本文地址:http://javascript.askforanswer.com/ruhequedingjavascriptshuzushifoubaohanjuyoudengyugeidingzhideshuxingdeduixiang.html
文章标签: ,  
版权声明:本文为原创文章,版权归 javascript 所有,欢迎分享本文,转载请保留出处!

文件下载

老薛主机终身7折优惠码boke112

上一篇:
下一篇:

评论已关闭!