【问题标题】:Removing All Elements with feature X from Array, except the latest从数组中删除所有具有特征 X 的元素,除了最新的
【发布时间】:2019-12-04 20:12:15
【问题描述】:

我有以下对象:

[
  { name: "Peter", id: 25, job: "carpenter" },
  { name: "Peter", id: 25, job: "shelf maker" },
  { name: "John", no: 20, job: "student" },
  { name: "John", id: 20, job: "university student" },
  { name: "John", id: 20, job: "student at uni still" },
  { name: "Jack", id: 20, job: "university student" }
]

我想遍历这个数组,每当nameid 相同时,我只想保留一个条目,即数组中出现最新的条目,然后丢弃其他的。我该怎么做?

我试过了

for(let i=0;i<people.length;i++) {
const person = people[i];
const result = people.filter(person => person.id === id && person.name === name);

people[i] = person;
}

...但这不起作用。任何想法我做错了什么?您将如何处理?

【问题讨论】:

  • 请告知预期输出

标签: javascript arrays node.js reactjs algorithm


【解决方案1】:

您可以使用reduceRight 来构建从数组末尾开始迭代的新数组,也可以使用Map 作为累加器值来存储key - value 对。

const data = [{"name":"Peter","id":25,"job":"carpenter"},{"name":"Peter","id":25,"job":"shelf maker"},{"name":"John","no":20,"job":"student"},{"name":"John","id":20,"job":"university student"},{"name":"John","id":20,"job":"student at uni still"},{"name":"Jack","id":20,"job":"university student"}]

const map = data.reduceRight((r, e) => {
  const key = `${e.name}|${e.id}`;
  if (!r.has(key)) r.set(key, e);
  return r;
}, new Map);

const uniq = [...map.values()];
console.log(uniq)

【讨论】:

  • 不错的方法,我正在考虑使用 reverse() 但最终没有打扰。我认为这个解决方案更快
  • @Kobe 谢谢,我也认为它更快,因为省略了反向步骤。
  • 我发现这个答案的唯一缺点是不得不再次分散这些值,除此之外,reduceRIght 是要走的路。
【解决方案2】:

我将reduce 放入一个对象中,其键是 ID 和名称放在一起,其值是迄今为止找到的具有特定 ID 和名称的最新对象,然后获取对象的值:

const input=[{name:"Peter",id:25,job:"carpenter"},{name:"Peter",id:25,job:"shelf maker"},{name:"John",no:20,job:"student"},{name:"John",id:20,job:"university student"},{name:"John",id:20,job:"student at uni still"},{name:"Jack",id:20,job:"university student"}];

const output = Object.values(
  input.reduce((a, obj) => {
    const { name, id } = obj;
    const key = `${name}_${id}`;
    a[key] = obj;
    return a;
  }, {})
);
console.log(output);

计算复杂度为O(N),因为没有嵌套循环。

【讨论】:

  • 这不是 O(2N),因为您使用的是 Object.values
  • Big O 复杂度忽略了那些不依赖于输入大小的因素(比如这里的标量乘数 2),因为它们与极限无关 - O(1000) === O(1) 甚至是真的,见en.wikipedia.org/wiki/Big_O_notation#Example
  • 啊,好的,谢谢你的澄清。我没有过多研究大 O 符号,这是有道理的。
【解决方案3】:

您可以使用reduceRightMap 来检查累加器中是否已经存在对象 - 如果存在,则忽略它,否则将新对象和新键 + 索引对推送到地图:

const arr = [
  { name: "Peter", id: 25, job: "carpenter" },
  { name: "Peter", id: 25, job: "shelf maker" },
  { name: "John", no: 20, job: "student" },
  { name: "John", id: 20, job: "university student" },
  { name: "John", id: 20, job: "student at uni still" },
  { name: "Jack", id: 20, job: "university student" }
];

const m = new Map([])
const output = arr.reduceRight((a, o, i) => (m.has(o.name + o.id) || a.push(o) && m.set(o.name + o.id, i), a), [])

console.log(output)

但是,常规的 for 循环是这里最快的解决方案:

const arr = [
  { name: "Peter", id: 25, job: "carpenter" },
  { name: "Peter", id: 25, job: "shelf maker" },
  { name: "John", no: 20, job: "student" },
  { name: "John", id: 20, job: "university student" },
  { name: "John", id: 20, job: "student at uni still" },
  { name: "Jack", id: 20, job: "university student" }
];

const m = new Map([])
const out = []

for (var i = arr.length - 1; i >= 0; i--) {
  const o = arr[i]
  if (!m.has(o.name + o.id)) {
    out.push(o)
    m.set(o.name + o.id, i)
  }
}


console.log(out)

查看性能测试here,使用更大的随机数组。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2014-08-16
    • 2023-03-09
    • 2021-11-01
    • 2010-12-01
    • 1970-01-01
    • 1970-01-01
    • 2016-02-12
    • 2020-08-29
    相关资源
    最近更新 更多