如何在对象数组中查找多个出现次数并增加计数值?

3

目前,我正在尝试计算对象数组内的多个出现次数,并将最终计数推入其中。我不想在另一个数组中存储数据。数据应保留在现有数组中。

我想添加计数的数组:

var array = [
    { artist: 'metallica', venue: 'olympiastadion' },
    { artist: 'foofighters', venue: 'wuhlheide' },
    { artist: 'metallica', venue: 'columbiahalle' },
    { artist: 'deftones', venue: 'columbiahalle' },
    { artist: 'deichkind', venue: 'wuhlheide' },
    { artist: 'metallica', venue: 'wuhlheide' },
    { artist: 'foofighters', venue: 'trabrennbahn' }
];

我目前的示例代码从数组中删除/减少元素,因此最终结果不符合要求:

var array = [
    { artist: 'metallica', venue: 'olympiastadion' },
    { artist: 'foofighters', venue: 'wuhlheide' },
    { artist: 'metallica', venue: 'columbiahalle' },
    { artist: 'deftones', venue: 'columbiahalle' },
    { artist: 'deichkind', venue: 'wuhlheide' },
    { artist: 'metallica', venue: 'wuhlheide' },
    { artist: 'foofighters', venue: 'trabrennbahn' }
];

array = Object.values(array.reduce((r, { artist, venue }) => {
    r[artist] = r[artist] || { artist, venue, count: 0 };
    r[artist].count++;
    return r;
}, {}));

console.log(array);

Which logs:
    { artist: 'metallica', venue: 'olympiastadion', count: 3 },
    { artist: 'foofighters', venue: 'wuhlheide', count: 2 },
    { artist: 'deftones', venue: 'columbiahalle', count: 1 },
    { artist: 'deichkind', venue: 'wuhlheide', count: 1 }

我会尽力做到以下结果:
var array = [
    { artist: 'metallica', venue: 'olympiastadion', count: 3 },
    { artist: 'foofighters', venue: 'wuhlheide', count: 2 },
    { artist: 'metallica', venue: 'columbiahalle', count: 3 },
    { artist: 'deftones', venue: 'columbiahalle', count: 1 },
    { artist: 'deichkind', venue: 'wuhlheide', count: 1 },
    { artist: 'metallica', venue: 'wuhlheide', count: 3 },
    { artist: 'foofighters', venue: 'trabrennbahn', count: 2 }
];

希望能指引我正确的方向,非常感谢任何帮助。

谢谢帮忙!期望的解决方案是:

var array = [{ artist: 'metallica', venue: 'olympiastadion' }, { artist: 'foofighters', venue: 'wuhlheide' }, { artist: 'metallica', venue: 'columbiahalle' }, { artist: 'deftones', venue: 'columbiahalle' }, { artist: 'deichkind', venue: 'wuhlheide' }, { artist: 'metallica', venue: 'wuhlheide' }, { artist: 'foofighters', venue: 'trabrennbahn' }],
    map = array.reduce( 
        (map, { artist }) => map.set(artist, (map.get(artist) || 0) + 1),
        new Map
    ),
    array = array.map(o => Object.assign({}, o, { count: map.get(o.artist) }));

console.log(array);

{ artist: 'metallica', venue: 'olympiastadion', count: 3 } 这段代码并没有太多意义。 - Andy
你想要更新同一个数组对象,还是创建一个新的数组并拥有独立的新对象? - Nina Scholz
@Andy 在这个微小的上下文环境中可能没有意义。 - huppen
4个回答

5

您可以先遍历所有项,然后将旧对象和新计数属性分配给一个新对象以获取计数。

var array = [{ artist: 'metallica', venue: 'olympiastadion' }, { artist: 'foofighters', venue: 'wuhlheide' }, { artist: 'metallica', venue: 'columbiahalle' }, { artist: 'deftones', venue: 'columbiahalle' }, { artist: 'deichkind', venue: 'wuhlheide' }, { artist: 'metallica', venue: 'wuhlheide' }, { artist: 'foofighters', venue: 'trabrennbahn' }],
    map = array.reduce( 
        (map, { artist }) => map.set(artist, (map.get(artist) || 0) + 1),
        new Map
    ),
    result = array.map(o => Object.assign({}, o, { count: map.get(o.artist) }));

console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }


使用Map作为计数器相比于使用对象有什么优势吗?(因为键是按插入顺序排序的或类似的原因?) - adiga
1
@adiga,Map#set 返回实例,并且不需要通过减少数组来降低开销。 - Nina Scholz

2
你可以按照以下步骤操作:
  • 使用reduce()从数组创建一个对象,该对象具有所有唯一艺术家的计数
  • 该对象将具有不同的键artists,它们的值将是它们的计数。
  • 然后在原始数组上使用forEach
  • 将所有的count设置为当前项中计数数组的艺术家值。
最初的回答:

var array = [
    { artist: 'metallica', venue: 'olympiastadion' },
    { artist: 'foofighters', venue: 'wuhlheide' },
    { artist: 'metallica', venue: 'columbiahalle' },
    { artist: 'deftones', venue: 'columbiahalle' },
    { artist: 'deichkind', venue: 'wuhlheide' },
    { artist: 'metallica', venue: 'wuhlheide' },
    { artist: 'foofighters', venue: 'trabrennbahn' }
];

const unique = array.reduce((ac,{artist:a}) => (ac[a] = ac[a] + 1 || 1,ac),{});
array.forEach(x => x.count = unique[x.artist]);
console.log(array)


谢谢指出,使用array.reduce也是一种可接受的解决方案。问题是,如果我想要一个额外的计数器"visit"来记录每个艺术家的出现次数,我该怎么做(这应该为每个艺术家增加不断增加的访问次数)? - huppen
这将添加一个名为“visit”的属性,其计数结果与计数变量相同。是否可能每次出现艺术家时都获得递增的访问量? - huppen
@huppen 这个 const unique = array.reduce((ac,{artist:a},i) => (array[i].visit = ac[a] = ac[a] + 1 || 1,ac),{}); 可能会解决你的问题。 - Maheer Ali
谢谢您的帮助。最后的代码解决了我在评论中提出的问题 :-) - huppen

0
你可以对数组进行两次迭代。
var array = [
    { artist: 'metallica', venue: 'olympiastadion' },
    { artist: 'foofighters', venue: 'wuhlheide' },
    { artist: 'metallica', venue: 'columbiahalle' },
    { artist: 'deftones', venue: 'columbiahalle' },
    { artist: 'deichkind', venue: 'wuhlheide' },
    { artist: 'metallica', venue: 'wuhlheide' },
    { artist: 'foofighters', venue: 'trabrennbahn' }
];

array.forEach(a => {
  if (!a.hasOwnProperty('count')) {
    Object.assign(a, { count: 0 });
  }
  array.forEach(b => {
    if (a.artist === b.artist) {
      a.count++;
    }
  });
});

console.log(array);

0
你可以对数组进行一次遍历,建立一个艺术家名称到计数的映射表,然后再进行第二次遍历,修改每个数组项并添加与艺术家相关联的计数。

var array = [
    { artist: 'metallica', venue: 'olympiastadion' },
    { artist: 'foofighters', venue: 'wuhlheide' },
    { artist: 'metallica', venue: 'columbiahalle' },
    { artist: 'deftones', venue: 'columbiahalle' },
    { artist: 'deichkind', venue: 'wuhlheide' },
    { artist: 'metallica', venue: 'wuhlheide' },
    { artist: 'foofighters', venue: 'trabrennbahn' }
];

var counts = array.reduce((counts, item) => {
  var artistName = item.artist;
  if (counts[artistName]) {
    counts[artistName] += 1;
  } else {
    counts[artistName] = 1;
  }
  
  return counts;
}, {});

array.forEach(item => item.count = counts[item.artist])

console.log(array);

.reduce函数是为了清晰而冗长的,但它可以大大缩短:

var array = [
    { artist: 'metallica', venue: 'olympiastadion' },
    { artist: 'foofighters', venue: 'wuhlheide' },
    { artist: 'metallica', venue: 'columbiahalle' },
    { artist: 'deftones', venue: 'columbiahalle' },
    { artist: 'deichkind', venue: 'wuhlheide' },
    { artist: 'metallica', venue: 'wuhlheide' },
    { artist: 'foofighters', venue: 'trabrennbahn' }
];

var counts = array.reduce((counts, item) => (counts[item.artist] = counts[item.artist] || 1, counts), {});

console.log(counts);

如果你想创建一个新的数组而不是修改旧数组中的对象,那么你可以复制每个对象和数组:

var array = [
    { artist: 'metallica', venue: 'olympiastadion' },
    { artist: 'foofighters', venue: 'wuhlheide' },
    { artist: 'metallica', venue: 'columbiahalle' },
    { artist: 'deftones', venue: 'columbiahalle' },
    { artist: 'deichkind', venue: 'wuhlheide' },
    { artist: 'metallica', venue: 'wuhlheide' },
    { artist: 'foofighters', venue: 'trabrennbahn' }
];

var counts = {
  "metallica": 3,
  "foofighters": 2,
  "deftones": 1,
  "deichkind": 1
}

var newArray = array.map(item => ({...item, count: counts[item.artist]}))

console.log(newArray);
console.log(array);


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