【问题标题】:Remove Duplicate In Array Using Pure Javascript Or Typescript [duplicate]使用纯 Javascript 或 Typescript 删除数组中的重复项 [重复]
【发布时间】:2019-03-02 00:19:00
【问题描述】:

我似乎只能找到使用其他 JS 库从数组中删除重复项的方法,但我希望在纯 JS 或 typescript 中执行此操作,因为我正在处理一个 Angular 项目。

我的问题是我可能会得到一个包含重复条目的数组,例如这个:

data [0: {Id: 1, Definition: "House"},
      1: {Id: 1, Definition: "House"}]

我想过滤掉它,以便我只得到

data [0: {Id: 1, Definition: "House"}]

我已经尝试过使用这种方法,但我仍然得到重复的条目

let uniqueArray = data.filter(function(item, pos) {
    return data.indexOf(item) == pos;
})

【问题讨论】:

  • data.indexOf(item) == pos 在您的情况下将始终为真,因为 find 将测试对象身份。您需要类似:jsfiddle.net/khrismuc/hnLowjy2
  • 你想如何过滤掉重复的条目?是不是只基于id键?
  • @Ashish 比较 ID 或 "Definition" 中的字符串...两者都可以工作

标签: javascript arrays typescript duplicates


【解决方案1】:

你可以通过这种方式实现你想要的:

您可以使用 'some' 检查最终数组中是否已经存在该值

data = [{Id: 1, Definition: "House"}, {Id: 1, Definition: "House"}]

const finalOut = []
data.forEach((value) => {
    if (!finalOut.some(x=> (x.Id === value.Id || x.Definition === value.Definition))) 
   {
        finalOut.push(value)
    }
})

您也可以通过'reduce' 以简洁优雅的方式实现此目的:

const finalOut2 = data.reduce((acc, cur) => acc.some(x=> (x.Id === cur.Id || x.Definition === cur.Definition)) ? acc : acc.concat(cur), [])

正如@Ezequiel 在forEachreduce 中使用some 所建议的那样,时间复杂度为n 平方的阶。对于较小的数据集,使用reducesome 是一种优雅的方法。但是,如果您正在处理长度非常大的数组,则必须避免 n 平方时间复杂度的顺序这是filter 的一种方法:

//Here storing every value of data is inside lookupObj after filtering it. 
//And checking if value is filtered based on if key of the value inside lookupObj

const lookupObj = {} 
const finalOut3 = data.filter(
    x => {
        const is_unique = !(lookupObj[`Id_${x.Id}`] || lookupObj[`Id_${x.Definition}`])
        lookupObj[`Id_${x.Id}`] = true
        lookupObj[`Id_${x.Definition}`] = true
        return is_unique
    }
)

【讨论】:

  • 谢谢,终于成功了!
  • 请注意,此方法在 O(n²) 或二次时间中运行,因为这里隐藏的是一个嵌套循环。这对于小型数组来说不是问题,但如果 data.length 变大,它会变慢。此答案中概述的其他方法在 O(n) 或线性时间内运行,并且不会遭受相同的命运。
  • 我已经用新函数更新了答案,以降低 O(n²) 复杂度。
【解决方案2】:

您可以使用对象的Id键在对象累加器中使用array#reduce获取唯一对象,并使用Object.values()获取该对象的所有对象。

let data = [{Id: 1, Definition: "House"},{Id: 1, Definition: "House"}, {Id: 2, Definition: "House2"}, {Id: 2, Definition: "House2"}],
    result = Object.values(data.reduce((r, o) =>  {
      r[o.Id] = r[o.Id] || {...o};
      return r;
    },{}));
console.log(result);

【讨论】:

  • 很遗憾我收到一个语法错误 [ts] 属性“values”不适用于“ObjectConstructor”类型
  • 你可以使用Object.prototype.values = function(obj) { var res = []; for (var i in obj) { if (obj.hasOwnProperty(i)) { res.push(obj[i]); } } return res; };
【解决方案3】:

如果 ID 决定身份,那么您可以使用 Map 或普通对象进行重复数据删除。相同的 ID 将在地图上占据相同的位置,因此您最终会得到唯一的对象(如果上述关于 ID 的假设成立)。

let data = [{Id: 1, Definition: "House"}, {Id: 1, Definition: "House"}];
let idToObj = {};
data.forEach((o) => idToObj[o.Id] = o);
let uniqueArray = Object.values(idToObj);

编辑:如果您想要相同但您可能拥有具有相同 ID 但在其他字段中不同的对象,则 Map 会派上用场,因为它可以将整个对象作为键:

let data = [{Id: 1, Definition: "House1"}, {Id: 1, Definition: "House2"}];
let map = new Map();
data.forEach((o) => map.set(o, true));
let uniqueArray = [...map.keys()];

【讨论】:

  • 哦,是的,现在修复了 :)
猜你喜欢
  • 2012-12-06
  • 2013-08-03
  • 2019-05-21
  • 2021-07-20
  • 1970-01-01
  • 2011-12-02
  • 2014-12-03
  • 1970-01-01
  • 2012-10-04
相关资源
最近更新 更多