создать уникальный список и количество элементов массива в массиве объектов - PullRequest
0 голосов
/ 25 сентября 2019

У меня есть следующий исходный массив:

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;

}, {});

есть ли лучший способ сделать это?или быстрее и чище?спасибо

Ответы [ 2 ]

2 голосов
/ 25 сентября 2019

Сначала я сгладил массивы, а затем сосчитал до 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 или flatten / group другим методом:

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 для создания объекта, как в третьем фрагменте)

0 голосов
/ 25 сентября 2019

Попробуйте использовать функциональное программирование: комбинация карты и 2 метода сокращения.

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)
...