js 对象数组排序+去重问题

思否 问答 👍 11 含 AI 优化版

问题

js 对象数组排序+去重问题

在 SegmentFault 查看原问题 →

由大模型辅助整理,保留原意,优化结构与可读性。

问题概述

有一个对象数组,其中 name 字段可能重复,需要按 name 去重,并且当出现重复项时,保留 created_at 时间最早的那一条记录。

涉及技术

Array.prototype.reduceArray.prototype.findIndex

期望结果

得到一个按 name 去重后的新数组,重复项按时间规则保留其中一条。

回答

原始回答

这是单纯的去重复你可以使用排序来完成时间操作。当然了,你也可以把重复再去比较时间的逻辑加在 reduce 里面

[
  {
    name: '玉骨遥寒薇结海报',
    created_at: '2021-06-04 04:54:06.164',
  },
  {
    name: '玉骨遥寒薇结海报',
    created_at: '2021-06-04 04:52:49.753',
  },
  {
    name: '玉骨遥寒薇结海报',
    created_at: '2021-06-04 05:02:02.398',
  },
  {
    name: '公交车抛锚警民携手推车为考生开路',
    created_at: '2021-06-04 04:52:40.588',
  },
  {
    name: '公交车抛锚警民携手推车为考生开路',
    created_at: '2021-06-04 05:07:21.587',
  },
].reduce(function(s,v){
    var itemIdx = s.findIndex(v1=>v1.name==v.name);
    if(itemIdx == -1){
        s.push(v)
    }else{
        var item = s[itemIdx];
        if(v.created_at < item.created_at){
            s.splice(itemIdx,1,v)
        }
    }
    
    return s
},[])

AI 优化 · 回答整理

解答思路

reduce 遍历原数组,累积一个去重后的结果数组:对每一项先用 findIndex 检查结果数组里是否已经存在同名的记录——不存在就直接加入;存在则比较 created_at,当前项时间更早就用它替换已存在的记录。

示例代码

const list = [
  { name: '玉骨遥寒薇结海报', created_at: '2021-06-04 04:54:06.164' },
  { name: '玉骨遥寒薇结海报', created_at: '2021-06-04 04:52:49.753' },
  { name: '玉骨遥寒薇结海报', created_at: '2021-06-04 05:02:02.398' },
  { name: '公交车抛锚警民携手推车为考生开路', created_at: '2021-06-04 04:52:40.588' },
  { name: '公交车抛锚警民携手推车为考生开路', created_at: '2021-06-04 05:07:21.587' },
];

const result = list.reduce((acc, cur) => {
  const idx = acc.findIndex((item) => item.name === cur.name);
  if (idx === -1) {
    acc.push(cur);
  } else {
    const existing = acc[idx];
    if (cur.created_at < existing.created_at) {
      acc.splice(idx, 1, cur);
    }
  }
  return acc;
}, []);

console.log(result);

详细说明

  • findIndex 用来判断结果数组中是否已经有同名记录,时间复杂度是 O(n),数据量大时可以考虑先用 Mapname 建立索引来优化到 O(1) 查找。
  • 时间字符串比较(cur.created_at < existing.created_at)能生效的前提是时间格式可以按字典序比较(如 YYYY-MM-DD HH:mm:ss.SSS),本例格式满足这个条件。
  • 数据量较大时更推荐使用 Map 优化版本:
const map = new Map();
for (const item of list) {
  const existing = map.get(item.name);
  if (!existing || item.created_at < existing.created_at) {
    map.set(item.name, item);
  }
}
const result2 = [...map.values()];

小结

小数据量用 reduce + findIndex 即可简洁实现按字段去重并保留特定记录;数据量较大时建议改用 Map 索引来提升查找效率。

由大模型辅助整理,保留原意,补充结构与代码格式。

回答转载自 SegmentFault

评论

评论功能即将开放。你也可以通过 邮件GitHub Issue 反馈。