【问题标题】:create unique list and count of array items in array of objects在对象数组中创建唯一列表和数组项计数
【发布时间】:2020-01-25 02:50:08
【问题描述】:

我有以下源数组:

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;

}, {});

有没有更好的方法呢?还是更快更清洁的方式?谢谢

【问题讨论】:

  • 您的预期输出在对象中首先具有最常出现的名称 - 这是必需的吗? (有可能实现,只是要求有点奇怪,因为好的脚本可能不应该依赖于属性顺序)
  • 是的,我也订购了

标签: javascript arrays for-loop ecmascript-6 reduce


【解决方案1】:

我先将数组展平,然后用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方法来创建对象,比如第三个sn-p)

【讨论】:

  • TypeError: list.flatMap 不是函数
  • 将其更改为[].concat(...list.map(({ students }) => students))list.map(({ students }) => students).flat()
  • @storis if list.flatMap is not a function,你运行的是什么浏览器或nodejs版本?
【解决方案2】:

尝试使用函数式编程: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)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-12-27
    • 1970-01-01
    • 2016-02-16
    • 1970-01-01
    • 2016-10-15
    • 1970-01-01
    • 2013-09-17
    相关资源
    最近更新 更多