javascript - 从数组中删除重复项只返回一个对象

标签 javascript arrays node.js json

我试图从这个 json 中删除重复的条目,但它只返回一个对象,我不明白我哪里出错了。

代码如下。

// exemplary array of objects (id 'NewLive' occurs twice)
var arr = [
{"jobcodeid":{"S":"Etc_new"}},
{"jobcodeid":{"S":"NewLive"}},
{"jobcodeid":{"S":"NewLiveVid"}},
{"jobcodeid":{"S":"New_Live"}},
{"jobcodeid":{"S":"New_Live_Vid"}},
{"jobcodeid":{"S":"Newest"}},
{"jobcodeid":{"S":"NewestLive"}},
{"jobcodeid":{"S":"NewestLiveVid"}},
{"jobcodeid":{"S":"Very_New_Vid"}},
{"jobcodeid":{"S":"Etc_new"}},
{"jobcodeid":{"S":"NewLive"}},
{"jobcodeid":{"S":"NewLiveVid"}},
{"jobcodeid":{"S":"New_Live"}},
{"jobcodeid":{"S":"New_Live_Vid"}},
{"jobcodeid":{"S":"Newest"}},
{"jobcodeid":{"S":"NewestLive"}},
{"jobcodeid":{"S":"NewestLiveVid"}},
{"jobcodeid":{"S":"Very_New_Vid"}}
],
    obj = {}, new_arr = [];

// in the end the last unique object will be considered
arr.forEach(function(v){
    obj[v['id']] = v;
   console.log(JSON.stringify(new_arr));
});
new_arr = Object.keys(obj).map(function(id) { return obj[id]; });

console.log(JSON.stringify(new_arr));

我也附上了 codepen。

https://codepen.io/anon/pen/oQXJWK

最佳答案

您的代码返回单个元素的原因是因为您正在使用 v['id'] 但对象上没有 id 属性,因此自始至终您正在一遍又一遍地设置 obj[undefined] 的循环。

尽管在您的 jsfiddle 代码中这看起来是正确的并且代码似乎按预期工作。

如果有人遇到这个问题是想了解如何从 javascript 中的数组中删除重复项,这里有几个选项:

经典方式:好旧的 for 循环

这基本上是您使用的解决方案,遍历数组,检查键是否已添加到结果数组中,如果不存在,则将元素添加到结果中。

示例:

const result = [];
const knownIDs = new Set();
for (const item of input) {
  if (!knownIDs.has(item.jobcodeid.S)) {
    result.push(item);
    knownIDs.add(item.jobcodeid.S);
  }
}

前往 map 并返回

要过滤重复项,您可以将元素转换为 Map键 -> 值,然后转换回数组。这是有效的,因为键在 Map 中是唯一的,并且重复项将被自动消除。这种方法的主要优点是,由于代码简单,错误较少​​。

console.log(
  Array.from(
    new Map(
      input.map(i => [i.jobcodeid.S, i])
    ).values()
  )
)

过滤和设置

另一种选择是使用Set 来记录已知的id 和filter删除具有已知 ID 的项目。这种方法的优点是它可能更容易阅读,因为意图是明确的。此外,这比转换为 Map 并返回的性能更高。

const knownKeys = new Set();
console.log(
  input.filter(i => {
    if (!knownKeys.has(i.jobcodeid.S)) {
      knownKeys.add(i.jobcodeid.S);
      return true;
   }
  })
);

查看它们的实际效果:

const input = [{"jobcodeid":{"S":"Etc_new"}},{"jobcodeid":{"S":"NewLive"}},{"jobcodeid":{"S":"NewLiveVid"}},{"jobcodeid":{"S":"New_Live"}},{"jobcodeid":{"S":"New_Live_Vid"}},{"jobcodeid":{"S":"Newest"}},{"jobcodeid":{"S":"NewestLive"}},{"jobcodeid":{"S":"NewestLiveVid"}},{"jobcodeid":{"S":"Very_New_Vid"}},{"jobcodeid":{"S":"Etc_new"}},{"jobcodeid":{"S":"NewLive"}},{"jobcodeid":{"S":"NewLiveVid"}},{"jobcodeid":{"S":"New_Live"}},{"jobcodeid":{"S":"New_Live_Vid"}},{"jobcodeid":{"S":"Newest"}},{"jobcodeid":{"S":"NewestLive"}},{"jobcodeid":{"S":"NewestLiveVid"}},{"jobcodeid":{"S":"Very_New_Vid"}}];

// Classic for loop
const result = [];
const knownIDs = new Set();
for (const item of input) {
  if (!knownIDs.has(item.jobcodeid.S)) {
    result.push(item);
    knownIDs.add(item.jobcodeid.S);
  }
}

console.log(result.map(r => r.jobcodeid.S));

// To Map and back
console.log(
  Array.from(
    new Map(
      input.map(i => [i.jobcodeid.S, i])
    ).values()
  )
)

// filter and set
const knownKeys = new Set();
console.log(
  input.filter(i => {
    if (!knownKeys.has(i.jobcodeid.S)) {
      knownKeys.add(i.jobcodeid.S);
      return true;
   }
  })
);

作为记录,我在公认的解决方案、我的解决方案和 Jacques' answer 的性能改进上运行了基准测试

accepted solution x 1,892,585 ops/sec ±3.48% (89 runs sampled)
Map and back x 495,116 ops/sec ±2.27% (90 runs sampled)
Set and filter x 1,600,833 ops/sec ±1.98% (90 runs sampled)
Jacques x 2,110,510 ops/sec ±0.98% (92 runs sampled)
Fastest is Jacques

如您所见,Jacques' solution确实快了一倍,所以如果你的目标是过滤巨大的数组或者如果性能是关键,你绝对应该选择它!

关于javascript - 从数组中删除重复项只返回一个对象,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53220284/

相关文章:

Javascript 变量显示未定义

html - NodeJS - 如何将相同的视频流传输到多个客户端?

javascript - 字符串替换在 jQuery 中的复选框取消选中事件中不起作用

javaScript 扫雷器显示空字段

javascript - 如何从异步调用返回响应?

Javascript 平均计算器(用户输入的多个值)

php - 访问关联数组 php pdo 时出现问题

Java,在声明需要宽度和高度的静态数组时遇到问题,直到我已经在函数中时才设置变量

javascript - 在创建electronicjs自动启动应用程序时遇到问题

macos - 在 mac 10.7.2 上安装 coffeescript 时出错