【问题标题】:How to filter an array of objects, based on some fields?如何根据某些字段过滤对象数组?
【发布时间】:2020-12-14 15:27:17
【问题描述】:

我有一个这样的对象数组:

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

]

我需要过滤它,只保留一个同名的,并且应该是id最高的那个。


const expectedOutput = [

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

]

我一直在苦苦挣扎,但找不到最佳解决方案。有什么想法吗?

【问题讨论】:

  • 这至少应该可以使用有点“手动”的方法来实现。到目前为止,您尝试了什么?
  • map、reduce 和 some 的组合,但我找不到合适的键
  • 如果您在问题中包含在内,您将更容易找出问题所在。

标签: javascript arrays sorting ecmascript-6


【解决方案1】:

跟踪对象映射名称到对象的最大值:

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

【讨论】:

    【解决方案2】:

    您可以使用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'
    }
    
    ];
    
    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);

    虽然这会很好用,因为您只需遍历数组一次。但是如果你使用 for 循环而不是 reduce。它会像for loops are usually faster than 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);

    【讨论】:

      【解决方案3】:

      由于数组已经按id 排序,您可以使用Map 对象并使用name 作为键设置每个值。如果存在,则覆盖先前的值。请注意,这仅符合要求,只要具有特定名称的最后一个元素也具有最高值。

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

      结果元素的顺序基于插入Map 对象的顺序。插入的第一个键将是结果数组的第一个元素。插入的第二个键将是第二个元素,等等。

      【讨论】:

        【解决方案4】:

        你可以使用Map Object来做到这一点。

        • 首先,创建一个新的地图对象
        • 使用forEach()方法遍历数组。
        • 将name作为键放入名为key的变量中
        • 在名为map 的Map Object 中使用has(key) 方法检查密钥是否存在
        • 如果键不存在,则通过调用set(key, value) 方法将其设置到映射对象中。在这个解决方案中,键是名称,值是对象。
        • 如果Key存在则使用get(key)方法获取对象,使用Math.max()方法获取最大id,然后更新对象并将其设置到Map对象中。

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

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2020-11-21
          • 1970-01-01
          • 2018-10-15
          • 2022-01-13
          • 2020-03-12
          • 2020-12-14
          • 2020-08-15
          • 1970-01-01
          相关资源
          最近更新 更多