Как посчитать и сгруппировать значения нескольких свойств в массиве объектов? - PullRequest
2 голосов
/ 01 марта 2020

У меня есть массив объектов:

[
  {'year': 2019, 'a_academic': 3, 'f_security': 4, ..., 'k_services': 3},
  {'year': 2019, 'a_academic': 2, 'f_security': 2, ..., 'k_services': 4},
  {'year': 2019, 'a_academic': 3, 'f_security': 3, ..., 'k_services': 1},
  ...
  {'year': 2019, 'a_academic': 3, 'f_security': 3, ..., 'k_services': 3},
]

Как подсчитать несколько значений свойств, затем сгруппировать их и сохранить в новом объекте, например:

{
  'a_academic': {
      4: 0,
      3: 3,
      2: 1,
      1: 0
  },
  'f_security': {
      4: 1,
      3: 2,
      2: 1,
      1: 0
  },
  ...,
  'k_services': {
      4: 1,
      3: 2,
      2: 0,
      1: 1
  }
}

I Я могу сделать это с помощью метода «уменьшить» и вручную получить доступ к ключу, но только для одного свойства:

let count = array.reduce((res, cur) => {
    res[cur.a_academic] = res[cur.a_academic] ? res[cur.a_academic] + 1 : 1;
    return res;
  }, {});

console.log(count);

Результат:

{
  3: 3,
  2: 1
}

Как эффективно реализовать это, чтобы оно работало для всех другие свойства, без ручного доступа к нему?

Ответы [ 5 ]

2 голосов
/ 01 марта 2020

Вы можете определить массив ключей, который вы хотите посчитать, а затем использовать метод reduce с вложенным forEach l oop на Object.entries и подсчитать встречающиеся значения для каждого из этих определенных ключей.

const data = [
  {'year': 2019, 'a_academic': 3, 'f_security': 4, 'k_services': 3},
  {'year': 2019, 'a_academic': 2, 'f_security': 2, 'k_services': 4},
  {'year': 2019, 'a_academic': 3, 'f_security': 3, 'k_services': 1},
  {'year': 2019, 'a_academic': 3, 'f_security': 3, 'k_services': 3},
]

const props = ['a_academic', 'f_security', 'k_services']

const result = data.reduce((r, e) => {
  Object.entries(e).forEach(([k, v]) => {
    if (props.includes(k)) {
      if (!r[k]) r[k] = {}
      r[k][v] = (r[k][v] || 0) + 1
    }
  })
  return r;
}, {})

console.log(result)

Чтобы заполнить пустые значения в каждом объекте, вы должны сначала найти минимальное и максимальное значения для всех данных, но также и для только определенных реквизитов.

const data = [
  {'year': 2019, 'a_academic': 3, 'f_security': 4, 'k_services': 3},
  {'year': 2019, 'a_academic': 2, 'f_security': 2, 'k_services': 4},
  {'year': 2019, 'a_academic': 3, 'f_security': 3, 'k_services': 1},
  {'year': 2019, 'a_academic': 3, 'f_security': 3, 'k_services': 3},
]

const props = ['a_academic', 'f_security', 'k_services']

const values = data.map(e => {
  return Object.entries(e)
    .filter(([k]) => props.includes(k))
    .map(([k, v]) => v)
}).flat()

const max = Math.max(...values)
const min = Math.min(...values)

const result = data.reduce((r, e) => {
  Object.entries(e).forEach(([k, v]) => {
    if (props.includes(k)) {
      if (!r[k]) {
        r[k] = {}

        for (let i = min; i <= max; i++) {
          r[k][i] = 0
        }
      }

      r[k][v] += 1
    }
  })
  return r;
}, {})


console.log(result)
1 голос
/ 01 марта 2020

Вам нужна вложенная группировка, опуская year от объектов.

var data = [{ year: 2019, a_academic: 3, f_security: 4, k_services: 3 }, { year: 2019, a_academic: 2, f_security: 2, k_services: 4 }, { year: 2019, a_academic: 3, f_security: 3, k_services: 1 }, { year: 2019, a_academic: 3, f_security: 3, k_services: 3 }],
    grouped = data.reduce((r, { year, ...o }) => {
        Object.entries(o).forEach(([k, v]) => {
            r[k] = r[k] || {};
            r[k][v] = (r[k][v] || 0) + 1;
        });
        return r;
    }, {});

console.log(grouped);
0 голосов
/ 01 марта 2020

Просто добавьте Object.keys l oop для своей логики c для динамического доступа к ключам.

const array = [
  { year: 2019, a_academic: 3, f_security: 4, k_services: 3 },
  { year: 2019, a_academic: 2, f_security: 2, k_services: 4 },
  { year: 2019, a_academic: 3, f_security: 3, k_services: 1 },
  { year: 2019, a_academic: 3, f_security: 3, k_services: 3 }
];

let count = array.reduce((res, cur) => {
  Object.keys(cur)
    .filter(key => key.includes("_"))
    .forEach(key => {
      const obj = res[key] || {};
      res[key] = {
        ...obj,
        [cur[key]]: (obj[cur[key]] || 0) + 1
      };
    });
  return res;
}, {});

console.log(count);
0 голосов
/ 01 марта 2020

Вы можете получить ключи от одного из ваших объектов (исключая year), а затем сопоставить каждый ключ с массивом. Например, a_academic имеет массив значений [3, 2, 3, 3], который сопоставлен с [0, 0, 1, 3, 0]. Используя этот массив total, вы можете использовать Object.assign(), чтобы присвоить его индексы объекту, который вы можете использовать для каждой группы следующим образом:

const arr = [
  {'year': 2019, 'a_academic': 3, 'f_security': 4, 'k_services': 3},
  {'year': 2019, 'a_academic': 2, 'f_security': 2, 'k_services': 4},
  {'year': 2019, 'a_academic': 3, 'f_security': 3, 'k_services': 1},
  {'year': 2019, 'a_academic': 3, 'f_security': 3, 'k_services': 3},
];

const groupArr = ([{year, ...first}, ...arr]) => {
  const ent = Object.entries(first);
  const gr = ent.map(([key, v]) => [v, ...arr.map(o => o[key])]);
  const maxN = Math.max(...gr.flat());
  const minN = Math.min(...gr.flat());
  
  const total = gr.map(arr =>
    arr.reduce((tally, n) => (tally[n]++, tally), Array(minN).concat(Array(maxN).fill(0)))
  );
  return Object.assign({}, ...ent.map(([k], i) => ({[k]: Object.assign({}, total[i])})));
}

console.log(groupArr(arr));
0 голосов
/ 01 марта 2020

Что вы сделали, это использовали значение из cur.academic вместо имени ключа. Чтобы лучше это объяснить, рассмотрим это

const obj = { alpha: 20, beta: 30, gamma: 40 };

console.log(obj['alpha']); // outputs 20

Что вы можете сделать так:

const array = [
  {'year': 2019, 'a_academic': 3, 'f_security': 4, 'k_services': 3},
  {'year': 2019, 'a_academic': 2, 'f_security': 2, 'k_services': 4},
  {'year': 2019, 'a_academic': 3, 'f_security': 3, 'k_services': 1},
  {'year': 2019, 'a_academic': 3, 'f_security': 3, 'k_services': 3},
];

const excludedKeys = ['year'];
let count = array.reduce((res, curr) => {
    // Select the keys you are going to use and exclude the ones you won't
    const keys = Object.keys(curr).filter(key => !excludedKeys.includes(key));

    keys.forEach(key => {
        res[key] = res[key] ? res[key] + 1 : 1;
    });

    return res;
}, {});

console.log(count);
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...