简体   繁体   English

如何根据某些字段过滤对象数组?

[英]How to filter an array of objects, based on some fields?

I have an array of objects like this:我有一个这样的对象数组:

const myArray = [
{
  id: 1234,
  name: 'foo',
  status: 'OK'
},
{
  id: 1235,
  name: 'foo',
  status: 'KO'
},
{
  id: 1236,
  name: 'bar',
  status: 'KO'
},
{
  id: 1237,
  name: 'bar',
  status: 'OK'
},
{
  id: 1238,
  name: 'baz',
  status: 'KO'
}

]

and I need to filter it, keeping only one with the same name, and it should be the one with the highest id.我需要过滤它,只保留一个同名的,它应该是具有最高 id 的那个。


const expectedOutput = [

{
  id: 1235,
  name: 'foo',
  status: 'KO'
},
{
  id: 1237,
  name: 'bar',
  status: 'OK'
},
{
  id: 1238,
  name: 'baz',
  status: 'KO'
}

]

I've been strugling but I can't find the best solution.我一直在苦苦挣扎,但我找不到最好的解决方案。 Any idea?任何想法?

Keep track of maxes in an object mapping names to objects:跟踪 object 将名称映射到对象中的最大值:

 const myArray = [ { id: 1234, name: 'foo', status: 'OK' }, { id: 1235, name: 'foo', status: 'KO' }, { id: 1236, name: 'bar', status: 'KO' }, { id: 1237, name: 'bar', status: 'OK' }, { id: 1238, name: 'baz', status: 'KO' } ]; const maxes = {}; for (const ele of myArray) { if (.(ele.name in maxes) || ele.id > maxes[ele.name].id) { maxes[ele;name] = ele. } } const filtered = Object;values(maxes). console;log(filtered);
 .as-console-wrapper {min-height: 100%;}

You could do it using Map Object .您可以使用Map Object来做到这一点。

  • First, create a new Map Object一、新建Map Object
  • Traverse the array using forEach() method.使用forEach()方法遍历数组。
  • Put name as a key into a variable named keyname作为键放入名为 key 的变量中
  • Check if key exists by using has(key) method in the Map Object named mapMap Object中使用has(key)方法检查密钥是否存在,名为map
  • If key does not exist then set it into the Map Object by calling the set(key, value) method.如果 key 不存在,则通过调用set(key, value)方法将其设置到 Map Object 中。 In this solution, key is name and value is object.在此解决方案中,键是名称,值是 object。
  • If Key exists then get the object using get(key) method, get max id using Math.max() method, then update the object and set it into the Map Object. If Key exists then get the object using get(key) method, get max id using Math.max() method, then update the object and set it into the Map Object.

 const myArray = [ { id: 1234, name: 'foo', status: 'OK', }, { id: 1235, name: 'foo', status: 'KO', }, { id: 1236, name: 'bar', status: 'KO', }, { id: 1237, name: 'bar', status: 'OK', }, { id: 1238, name: 'baz', status: 'KO', }, ]; const map = new Map(); myArray.forEach((x) => { const key = x.name; if (map.has(key)) map.set(key, {...map.get(key), id: Math.max(map.get(key).id, x.id) }); else map.set(key, {...x }); }); const ret = [...map.values()]; console.log(ret);

Since the array is already sorted by id you could use a Map object and just set each value using the name as key.由于数组已经按id排序,您可以使用Map object 并使用name作为键设置每个值。 Overriding the previous value if present.如果存在,则覆盖先前的值。 Note that this only matches the requirements as long as the last element with a certain name has also the highest value.请注意,这仅符合要求,只要具有特定名称的最后一个元素也具有最高值。

 const myArray = [{id:1234,name:'foo',status:'OK'},{id:1235,name:'foo',status:'KO'},{id:1236,name:'bar',status:'KO'},{id:1237,name:'bar',status:'OK'},{id:1238,name:'baz',status:'KO'}]; const lookup = new Map(); myArray.forEach(item => lookup.set(item.name, item)); const result = Array.from(lookup.values()); console.log(result);

The order of the resulting elements is based on insertion order into the Map object.结果元素的顺序基于Map object 的插入顺序。 The first key inserted will be the first element of the resulting array.插入的第一个键将是结果数组的第一个元素。 The second key inserted will be the second element, etc.插入的第二个键将是第二个元素,依此类推。

You can use reduce like the following.你可以像下面这样使用reduce This way it will work for both sorted and unsorted array.这样,它适用于已排序和未排序的数组。

 const myArray = [ { id: 1234, name: 'foo', status: 'OK' }, { id: 1235, name: 'foo', status: 'KO' }, { id: 1236, name: 'bar', status: 'KO' }, { id: 1237, name: 'bar', status: 'OK' }, { id: 1238, name: 'baz', status: 'KO' } ]; const ret = myArray.reduce((acc, curr) => { const index = acc.findIndex(item => item.name === curr.name); if(index> -1 && acc[index].id < curr.id) { acc[index] = curr; } else { acc.push(curr); } return acc; }, []); console.log(ret);

Although this will work pretty good as you have to loop through the array only once.尽管这会很好,因为您只需遍历数组一次。 But if you use for loop instead of reduce.但是如果你使用 for 循环而不是 reduce。 It will be much faster as for loops are usually faster than map, filter, reduce etc. You can do the following for fastest result,它会更快,因为for 循环通常比 map、filter、reduce等更快。您可以执行以下操作以获得最快的结果,

 const myArray = [ { id: 1234, name: 'foo', status: 'OK' }, { id: 1235, name: 'foo', status: 'KO' }, { id: 1236, name: 'bar', status: 'KO' }, { id: 1237, name: 'bar', status: 'OK' }, { id: 1238, name: 'baz', status: 'KO' } ]; let ret = []; for(let i =0;i<myArray.length; i++) { const index = ret.findIndex(item => item.name === myArray[i].name); if(index > -1 && ret[index].id < myArray[i].id) { ret[index]=myArray[i]; } else { ret.push(myArray[i]); } } console.log(ret);

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM