如何计算数组中的相同对象属性值

时间:2018-12-03 21:14:52

标签: javascript arrays

我有一个具有以下结构的大型阵列:

let data = [
  {
    name: 'name1',
    values: {...},
  },
  {
    name: 'name1',
    values: {...},
  },
  {
    name: 'name2',
    values: {...},
  },
  {
    name: 'name1',
    values: {...},
  },
  {
    name: 'name3',
    values: {...},
  },
  ...
]

我需要找到一种方法来计算每个名称在数据数组中作为名称值出现的频率。

因此,在此示例中,结果应类似于以下数组:

let nameCounts = [
  {
     name: 'name1'
     count: 3
  },
  {
     name: 'name2'
     count: 1
  },
  {
     name: 'name3'
     count: 1
  }
]

我正在努力寻找解决此问题的好方法。有什么想法吗?

4 个答案:

答案 0 :(得分:7)

您可以reduce数组到一个对象,该对象的名称为键,“计数对象”为值。然后,您可以使用Object.values获得最终数组:

let data = [{
    name: 'name1',
    values: {},
  },
  {
    name: 'name1',
    values: {},
  },
  {
    name: 'name2',
    values: {},
  },
  {
    name: 'name1',
    values: {},
  },
  {
    name: 'name3',
    values: {},
  }
];

var res = Object.values(data.reduce((a, {name}) => {
  a[name] = a[name] || {name, count: 0};
  a[name].count++;
  return a;
}, Object.create(null)));

console.log(res);

请注意,我使用object destructuring从reduce回调中的每个“当前”对象获取name值。 ||模式是JS领域的标准做法,如果不存在默认值,则分配默认值。

也请注意@ibrahimmahrir关于使用Object.create(null)为累加器创建无原型对象的评论。

答案 1 :(得分:1)

使用Array#reduceArray#map的替代解决方案。

const data = [{name:'name1'},{name:'name1'},{name:'name2'},{name:'name1'},{name:'name3'}];

const q = data.reduce((s, { name }) => (s[name] = (s[name] || 0) + 1, s), {});
const r = Object.keys(q).map((key) => ({ name: key, count: q[key] }));

console.log(r);

答案 2 :(得分:1)

我将使用Array.prototype.reduce()创建一个以name部分为键的对象,并让计数累积为该对象的值,然后使用Object.prototype.entries()将其转换回放入数组。

const reducer = (acc, {name}) => {
    acc[name] = acc[name] || 0
    acc[name] += 1
    return acc
}

data.reduce(reducer, {})
    .entries()
    .forEach(([name, count]) => { name, count})

答案 3 :(得分:1)

另一种解决方法是使用Array.reduceMap,因为Map是为此而生的:)

let data = [{ name: 'name1', values: {}, }, { name: 'name1', values: {}, }, { name: 'name2', values: {}, }, { name: 'name1', values: {}, }, { name: 'name3', values: {}, } ];

const countBy = (arr, prop) => arr.reduce((r,c,i,a) => {
  r.set(c[prop], (r.get(c[prop]) || 0) + 1)  
  return i == a.length-1 ? 
    Array.from(r).map(([k,v]) => ({ name: k, count: v })) : r
}, new Map())

console.log(countBy(data, 'name'))

我以模仿lodash _.countBy(如果您使用的话,不会比这更简洁)的功能的形式实现它,但输出略有不同:

let data = [{ name: 'name1', values: {}, }, { name: 'name1', values: {}, }, { name: 'name2', values: {}, }, { name: 'name1', values: {}, }, { name: 'name3', values: {}, } ];

console.log(_.countBy(data, 'name'))
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.10/lodash.min.js"></script>