Сортировать и сгруппировать массив объектов по двум ключам и создать массив сгруппированных элементов с новыми ключами - PullRequest
0 голосов
/ 28 января 2020

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

const items = [
  { name: 'john', class: 'one', section: 'a' },
  { name: 'john2', class: 'one', section: 'b' },
  { name: 'john3', class: 'one', section: 'a' },
  { name: 'john4', class: 'two', section: 'a' },
  { name: 'john5', class: 'two', section: 'b' },
  { name: 'john6', class: 'two', section: 'b' },
  { name: 'john7', class: 'three', section: 'a' },
  { name: 'john8', class: 'four', section: 'a' },
  { name: 'john9', class: 'four', section: 'b' }
];

Я бы хотел сгруппировать его таким образом:

[
    {
        'oneA': [
            { name: 'john', class: 'one', section: 'a' },
            { name: 'john3', class: 'one', section: 'a' }
        ]
    },
    {
        'oneB': [
            { name: 'john2', class: 'one', section: 'b' }
        ]
    },
    {
        'twoA': [
            { name: 'john4', class: 'two', section: 'a' }
        ]
    },
    {
        'twoB': [
            { name: 'john5', class: 'two', section: 'b' },
            { name: 'john6', class: 'two', section: 'b' }
        ]
    },
    {
        'threeA': [
            { name: 'john7', class: 'three', section: 'a' }
        ]
    },
    {
        'fourA': [
            { name: 'john8', class: 'four', section: 'a' }
        ]
    },
    {
        'fourB': [
            { name: 'john9', class: 'four', section: 'b' }
        ]
    }
]

Я пробовал что-то вроде этого:

items.sort(function (a, b) {
  if (a.class > b.class) return 1;
  if (a.class < b.class) return -1;

  if (a.section > b.section) return 1;
  if (a.section < b.section) return -1;
})

Это упорядочивает массив так, как я хочу, но он не группируется, как я описал выше. Вы знаете способ достичь этого?

Ответы [ 5 ]

2 голосов
/ 28 января 2020

Вы можете просто сгруппировать их, взяв Map.

. Он генерирует ключ class и заглавные буквы section, пытается получить значение из карты или возьмите пустой массив для распределения в новом массиве фактического объекта. Затем он устанавливает этот массив как новое значение на карте.

Array.from получает все пары ключ / значение с карты и создает новые объекты с вычисляемым именем свойства .

const
    getKey = o => `${o.class}${o.section.toUpperCase()}`,
    items = [{ name: 'john', class: 'one', section: 'a' }, { name: 'john2', class: 'one', section: 'b' }, { name: 'john3', class: 'one', section: 'a' }, { name: 'john4', class: 'two', section: 'a' }, { name: 'john5', class: 'two', section: 'b' }, { name: 'john6', class: 'two', section: 'b' }, { name: 'john7', class: 'three', section: 'a' }, { name: 'john8', class: 'four', section: 'a' }, { name: 'john9', class: 'four', section: 'b' }],
    result = Array.from(
        items.reduce(
            (m, o) => m.set(getKey(o), [...(m.get(getKey(o)) || []), o]),
            new Map
        ),
        ([k, v]) => ({ [k]: v })
    );

console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
1 голос
/ 28 января 2020
const items = [
    { name: 'john', class: 'one', section: 'a' },
    { name: 'john2', class: 'one', section: 'b' },
    { name: 'john3', class: 'one', section: 'a' },
    { name: 'john4', class: 'two', section: 'a' },
    { name: 'john5', class: 'two', section: 'b' },
    { name: 'john6', class: 'two', section: 'b' },
    { name: 'john7', class: 'three', section: 'a' },
    { name: 'john8', class: 'four', section: 'a' },
    { name: 'john9', class: 'four', section: 'b' }
];

let newArray = items.reduce((main, curr) => {
    let index = main.findIndex(obj => Object.keys(obj).includes(curr.class + curr.section))
    if (index == -1) main.push({ [curr.class + curr.section]: [curr] })
    else main[index][curr.class + curr.section].push(curr)
    return main
}, [])
console.log(newArray)
0 голосов
/ 28 января 2020

Если вы ожидаете ответа простым javascript для лучшего понимания без использования встроенных функций.

var items = [
    { name: 'john', class: 'one', section: 'a' },
    { name: 'john2', class: 'one', section: 'b' },
    { name: 'john3', class: 'one', section: 'a' },
    { name: 'john4', class: 'two', section: 'a' },
    { name: 'john5', class: 'two', section: 'b' },
    { name: 'john6', class: 'two', section: 'b' },
    { name: 'john7', class: 'three', section: 'a' },
    { name: 'john8', class: 'four', section: 'a' },
    { name: 'john9', class: 'four', section: 'b' }
];
var resultArray =[];
for(var i=0;i<items.length;i++){
    if(resultArray[items[i]['class']+items[i]['section'].toUpperCase()]){
        resultArray[items[i]['class']+items[i]['section'].toUpperCase()].push(items[i]);
    } else {
        var a ="";
        a = items[i]['class']+items[i]['section'].toUpperCase();
        resultArray[a]=[];
        resultArray[a].push(items[i])
    }
}

console.log(resultArray);

enter image description here

0 голосов
/ 28 января 2020

Вы можете использовать reduce функцию как:

const items = [
  { name: 'john', class: 'one', section: 'a' },
  { name: 'john2', class: 'one', section: 'b' },
  { name: 'john3', class: 'one', section: 'a' },
  { name: 'john4', class: 'two', section: 'a' },
  { name: 'john5', class: 'two', section: 'b' },
  { name: 'john6', class: 'two', section: 'b' },
  { name: 'john7', class: 'three', section: 'a' },
  { name: 'john8', class: 'four', section: 'a' },
  { name: 'john9', class: 'four', section: 'b' }
];

const groupedItems = items.reduce((result, current) => {
  const key = current.class + current.section.toUpperCase();
  
  if (Array.isArray(result[key])) {
    result[key].push(current);
  } else {
    result[key] = [current];
  }
  
  return result;
}, {});

const expectedResult = Array.from(Object.keys(groupedItems), (elem) => ({[elem]: groupedItems[elem]}));

console.log(expectedResult);
0 голосов
/ 28 января 2020

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

Чтобы решить вашу проблему, просто переберите все элементы и проверьте, есть ли у вашего результирующего объекта требуемый ключ. Если нет, создайте его, а затем вставьте текущий элемент в соответствующий массив.

const items = [
  { name: 'john', class: 'one', section: 'a' },
  { name: 'john2', class: 'one', section: 'b' },
  { name: 'john3', class: 'one', section: 'a' },
  { name: 'john4', class: 'two', section: 'a' },
  { name: 'john5', class: 'two', section: 'b' },
  { name: 'john6', class: 'two', section: 'b' },
  { name: 'john7', class: 'three', section: 'a' },
  { name: 'john8', class: 'four', section: 'a' },
  { name: 'john9', class: 'four', section: 'b' }
];

let result = {};

items.forEach(item => {
  let key = `${item.class}${item.section.toUpperCase()}`;
  if(!result.hasOwnProperty(key)) {
    result[key] = [];
  }
  result[key].push(item);
});

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