我有以下源数组:
const list = [
{
students: [ 'peter', 'bob', 'john']
},
{
students: [ 'thomas', 'sarah', 'john']
},
{
students: [ 'john', 'sarah', 'jack']
}
];
我想获得唯一的学生姓名和人数,最终结果应该是:
{
'john': 3,
'sarah': 2,
'thomas': 1,
'jack': 1,
'peter': 1,
'bob': 1
}
这是我的尝试:
const unique = list.reduce(function(total, curr){
const students = curr.students;
for (c of students) {
if (!total[c]) {
total[c] = 1
} else {
total[c] += 1;
}
}
return total;
}, {});
有更好的方法吗?还是更快更清洁的方式?谢谢
答案 0 :(得分:2)
我先将数组展平,然后用reduce
进行计数:
const list = [
{
students: [ 'peter', 'bob', 'john']
},
{
students: [ 'thomas', 'sarah', 'john']
},
{
students: [ 'john', 'sarah', 'jack']
}
];
const allStudents = list.flatMap(({ students }) => students);
const count = allStudents.reduce((a, name) => {
a[name] = (a[name] || 0) + 1;
return a;
}, {});
console.log(count);
如果您还希望对属性进行排序,则将对象的Object.entries
进行排序,然后使用Object.fromEntries
将其变回对象:
const list = [
{
students: [ 'peter', 'bob', 'john']
},
{
students: [ 'thomas', 'sarah', 'john']
},
{
students: [ 'john', 'sarah', 'jack']
}
];
const allStudents = list.flatMap(({ students }) => students);
const count = allStudents.reduce((a, name) => {
a[name] = (a[name] || 0) + 1;
return a;
}, {});
const sorted = Object.fromEntries(
Object.entries(count).sort((a, b) => b[1] - a[1])
);
console.log(sorted);
如果您的环境不支持flatMap或fromEntries,请使用polyfill或通过其他方法展平/分组:
const list = [
{
students: [ 'peter', 'bob', 'john']
},
{
students: [ 'thomas', 'sarah', 'john']
},
{
students: [ 'john', 'sarah', 'jack']
}
];
const allStudents = [].concat(...list.map(({ students }) => students));
const count = allStudents.reduce((a, name) => {
a[name] = (a[name] || 0) + 1;
return a;
}, {});
const sortedEntries = Object.entries(count).sort((a, b) => b[1] - a[1]);
const sortedObj = sortedEntries.reduce((a, [prop, val]) => {
a[prop] = val;
return a;
}, {});
console.log(sortedObj);
请记住,对象属性顺序仅在ES6 +环境中指定。尽管规范未保证Object.fromEntries
会按照与条目相同的顺序创建对象,但幸运的是,在我遇到的任何实现中,它仍然会做。 (如果您仍然担心它,可以使用老式的reduce
方法来创建对象,就像在第三段中一样)
答案 1 :(得分:0)
尝试使用函数式编程:map和2 reduce方法的组合。
const listMapped = list.map(it=> it.students)
const listReduced = listMapped.reduce((acc, rec) => {
return [...acc.concat(rec)]
}, [])
const listCounted = listReduced.reduce((acc, rec) => {
acc[rec]
? acc[rec] += 1
: acc[rec] = 1
return acc
}, {})
console.log(listCounted)