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

Пожалуйста, ознакомьтесь с моей скрипкой , которая включает в себя весь следующий код.

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

Я начинаю с этого формата данных:

const originalData = [
  {
    "groupId": 0,
    "color": "red",
    "shape": "circle"
  },
  {
    "groupId": 1,
    "color": "green",
    "shape": "square"
  },
  {
    "groupId": 1,
    "color": "orange",
    "shape": "hexagon"
  },
  {
    "groupId": 1,
    "color": "purple",
    "shape": "triangle"
  },
  {
    "groupId": 2,
    "color": "aqua",
    "shape": "diamond"
  },
  {
    "groupId": 2,
    "color": "blue",
    "shape": "trapezoid"
  }
];

И я хотел бы преобразовать его в новый массив объектов, сгруппированных по значению свойства groupId:

const desiredData = [
  {
    "groupId": 0,
    "items": [
      {
        "color": "red",
        "shape": "circle"
      }
    ]
  },
  {
    "groupId": 1,
    "items": [
      {
        "color": "green",
        "shape": "square"
      },
      {
        "color": "orange",
        "shape": "hexagon"
      },
      {
        "color": "purple",
        "shape": "triangle"
      }
    ]
  },
  {
    "groupId": 2,
    "items": [
      {
        "color": "aqua",
        "shape": "diamond"
      },
      {
        "color": "blue",
        "shape": "trapezoid"
      }
    ]
  }
];

Эта функция сокращения (которую я нашел в MDN ) ближе всего я смог прийти к преобразованию моих данных. К сожалению, мое понимание Javascript ограничено, и я не уверен, как добавить поля (например, group) в процессе преобразования. Кроме того, результатом является объект, а не массив объектов.

const actualFormattedData = originalData.reduce((acc, obj) => {
  let key = obj['groupId'];
  if (!acc[key]) {
    acc[key] = [];
  }
  acc[key].push(obj);
  return acc;
}, {});

Вывод из функции сокращения:

{
  "0": [
    {
      "groupId": 0,
      "color": "red",
      "shape": "circle"
    }
  ],
  "1": [
    {
      "groupId": 1,
      "color": "green",
      "shape": "square"
    },
    {
      "groupId": 1,
      "color": "orange",
      "shape": "hexagon"
    },
    {
      "groupId": 1,
      "color": "purple",
      "shape": "triangle"
    }
  ],
  "2": [
    {
      "groupId": 2,
      "color": "aqua",
      "shape": "diamond"
    },
    {
      "groupId": 2,
      "color": "blue",
      "shape": "trapezoid"
    }
  ]
}

Конечная цель состоит в том, чтобы отобразить массив объектов в React. , Я знаю, что могу использовать Object.entries и индексы массивов для достижения аналогичного результата с actualFormattedData как есть, но было бы идеально, если бы я мог сначала сделать actualFormattedData похожим на desiredData.

Спасибо за ваше время!

Ответы [ 5 ]

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

Это должно работать:

const dict = originalData.reduce((acc, obj) => {
  let groupId = obj['groupId'];
  delete obj.groupId;
  if (!acc[groupId]) {
    acc[groupId] = { // here is where we add the fields you wanted
        groupId,
        items: []
      };
  }
  acc[groupId].items.push(obj);
  return acc;
}, {});

// turn this into an array, just getting the values of the fields in the dictionary
const actualFormattedData = Object.values(dict);
0 голосов
/ 29 января 2020

Другим простым способом группировки по имени свойства может быть использование loda sh.

let groupedData = _.groupBy(rawData, dataObj => dataObj.propertyToGroupBy)

Где groupedData - это результат, который вы ищете, rawData - исходные данные и propertyToGroupBy это свойство объекта, с которым вы хотите сгруппировать.

Вы можете проверить этот ответ.

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

Вот простое для понимания решение:

const originalData = [
  {
    "groupId": 0,
    "color": "red",
    "shape": "circle"
  },
  {
    "groupId": 1,
    "color": "green",
    "shape": "square"
  },
  {
    "groupId": 1,
    "color": "orange",
    "shape": "hexagon"
  },
  {
    "groupId": 1,
    "color": "purple",
    "shape": "triangle"
  },
  {
    "groupId": 2,
    "color": "aqua",
    "shape": "diamond"
  },
  {
    "groupId": 2,
    "color": "blue",
    "shape": "trapezoid"
  }
];
const data = [];
const dataObjIndex = id=>{
  for(let i=0,l=data.length; i<l; i++){
    if(data[i].groupId === id){
      return i;
    }
  }
  return -1;
}
originalData.forEach(o=>{
  let i = dataObjIndex(o.groupId);
  if(i === -1){
    i = data.length; data.push({groupId:o.groupId, items:[]});
  }
  data[i].items.push({color:o.color, shape:o.shape});
});
console.log(data);
0 голосов
/ 29 января 2020

Вот ваше решение для скрипки

https://jsfiddle.net/07n9ks86/

и ключевой код для него (n2):

const formattedData = originalData.reduce((acc, curr) => {
  console.log(acc)
  const index = acc.findIndex(x => x.group === curr.group);
  if (index > 0) {
    acc[index] = {
      ...acc[index],
      items: [...acc[index].items,
        {
          'color': curr.color,
          'shape': curr.shape
        }
      ]
    }
  } else {
    acc.push({
      group: curr.group,
      items: [{
        'color': curr.color,
        'shape': curr.shape
      }]
    })
  }
  return acc;
}, []);
0 голосов
/ 29 января 2020

Простое решение может быть достигнуто с помощью одного вызова Array#reduce(), как подробно описано во фрагменте кода ниже.

Просто обратите внимание, что это решение подчеркивает простоту, а не эффективность, и, как правило, не подходит для очень больших входных массивов:

const originalData=[{groupId:0,color:"red",shape:"circle"},{groupId:1,color:"green",shape:"square"},{groupId:1,color:"orange",shape:"hexagon"},{groupId:1,color:"purple",shape:"triangle"},{groupId:2,color:"aqua",shape:"diamond"},{groupId:2,color:"blue",shape:"trapezoid"}];

/* Use reduce to iterate and transform originalData array to desired result */
const desiredData = originalData.reduce((result, item) => {
  
  /* The group item to add from this iteration */
  const groupItem = { color : item.color, shape : item.shape };
  
  /* Search for item that already exists with matching group id */
  const existingGroup = result.find(resultItem => resultItem.groupId === item.groupId);
  if(existingGroup) {
    /* Add item to group if found */
    existingGroup.items.push(groupItem);
  }
  else {
    /* Add group with item if not group found */
    result.push({ 
      groupId : item.groupId,
      items : [ groupItem ]
    });
  }
  
  return result;
  
}, []);

console.log(desiredData);

Надеюсь, это поможет!

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