JavaScript:筛选具有特定出现次数的重复元素的数组

4

我有一个包含重复名称的数组。

let arr = ['John', 'Jack', 'John', 'Jack', 'Jack', 'June', 'June'];

我想创建一个新的数组,其中包含一些重复元素,并指定它们出现的实例。
例如,我可能只想让数组包含 John、Jack 和 June 的第二次出现。该数组将如下所示:
'John', 'Jack', 'June'

为实现这个目标,我声明了一个对象ni,并循环遍历arr将属性添加到对象中,每个属性对应于一个名称;该属性将保存一个包含每个名称出现的所有索引的数组。
let ni  = {};

for(let i = 0; i < arr.length; i++) {
  let name = arr[i];
  if(nc.hasOwnProperty(name)) {
    ni[name].push(i);
  } else {
    ni[name] = [i];
  }
}

console.log(ni);
// > Object { John: Array [0, 2], Jack: Array [1, 3, 4], June: Array [5, 6] }

在我的 Array.filter 函数中,我检查元素的索引是否等于对象属性相同名称的索引 1。
let newArr = arr.filter(function(name) {
  if(ni.hasOwnProperty(name)) {
    return arr.indexOf(name) === ni[name][1];
  }
});

这应该将John索引2Jack索引3,以及June索引6返回到新数组中。

然而,这并没有起作用。将newArr记录到控制台将输出一个与原始值完全相同的数组。

> Array ["John", "Jack", "John", "Jack", "Jack", "June", "June"]

2
所以,基本上返回出现次数大于一的名称? - adiga
与您所声称的相反,通过过滤器返回的 newArr 是空的。 - trincot
可能是[获取JavaScript数组中所有唯一值(删除重复项)]的重复问题(https://dev59.com/PXI-5IYBdhLWcg3wO1rl)。 - Jack Templeman
3个回答

2
你可以使用reduce来计算每个名字的出现次数。如果名字的计数为2,则将其推送到另一个数组中。这样你就不必运行嵌套的数组方法:

const array = ['Jane', 'John', 'Jack', 'John', 'Jack', 'Jack', 'June', 'June'];
const filtered = [];
const count = array.reduce((a, name) => {
  a[name] = a[name] + 1 || 1;
  if(a[name] === 2)
    filtered.push(name)
  
  return a;
}, {});

console.log(filtered)

获取计数器键值大于1的计数器。

const array = ['Jane', 'John', 'Jack', 'John', 'Jack', 'Jack', 'June', 'June'],
      count = array.reduce((a, n) => (a[n] = a[n] + 1 || 1, a), {}),
      filtered = Object.keys(count).filter(n => count[n] > 1);
      
console.log(filtered)


2
您可以使用一些简单的数组逻辑,如下所示:
最初的回答:您可以使用一些简单的数组逻辑,如下所示:
let newArr = arr.filter((e, i) => i == ni[e][1]);

如果数组不包含足够的元素 - 即如果它未定义,它将取代数组的最后一个元素。 - Jack Bashford
但对于非空字符串,它将始终为真(请注意,“==”优先于“||”)。其次,这会打败目的,因为“length”可能为1,然后您会得到第一个出现。OP想要第二个... - trincot
那我应该删除 || 部分吗? - Jack Bashford
是的,我本来也打算和你一起回答,但只有那个细微的差别,所以最好你不要加上它。 - trincot
好的,感谢你的反馈@trincot。我还在完善自己有关优先级的知识,我会记住你提到的内容。 - Jack Bashford

1
我创建了一个对象而不是数组,因为它似乎更适合从名称映射到第二个出现的索引。它的工作原理如下:indexOf返回数组中元素的第一次出现的索引,如果indexOf不等于当前索引,则它是第二次或之后的出现,然后我检查名称是否已经在返回对象中,这样我就知道它不是第三次或之后的出现。

let arr = ['John', 'Jack', 'John', 'Jack', 'Jack', 'June', 'June'];
let newObj = arr.reduce(function(acc, cur, idx) {
  if (arr.indexOf(cur)!==idx && !acc[cur]) { acc[cur] = idx; }
 return acc;
}, {});
console.log(newObj);


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接