Home > Enterprise >  Mapping through array and grouping where property is the same
Mapping through array and grouping where property is the same

Time:02-06

I have an array returning like so:

errors = [
    {
        "row": 1,
        "key": "volume",
        "errorType": "Data type",
        "expectedType": "number",
        "receivedType": "string"
    },
    {
        "row": 1,
        "key": "units",
        "errorType": "Required data",
        "expectedType": "string"
    },
    {
        "row": 3,
        "key": "year",
        "errorType": "Incorrect data type",
        "expectedType": "number",
        "receivedType": "string"
    },
    {
        "row": 3,
        "key": "make",
        "errorType": "Required data",
        "expectedType": "string"
    }
]

I would like to return an array of objects as below:

const errorGrouped = [
  {
  row:1,
  data:[
    {
      "key":"volume",
      "errorType": "Data type",
      "expectedType": "number",
      "receivedType": "string"
    },
    {
      "key": "units",
      "errorType": "Required data",
      "expectedType": "string"
    }
  ]
  },
  {
  row:3,
  data:[
    {
      "key": "year",
      "errorType": "Incorrect data type",
      "expectedType": "number",
      "receivedType": "string"
    },
    {
      "key": "make",
      "errorType": "Required data",
      "expectedType": "string"
    }
  ]
  }
]

I have had a go mapping through each object, destructuring into my required form of [{row:.., data:[...]}] but then I can't see an obvious and clean way to group - which suggests to me there's a better way to do this.

But yes, appreciate any help people can provide. Thanks

CodePudding user response:

You can use reduce method in JS.

const errorGrouped = errors.reduce((accumulatorList, error) => {
    const group = accumulatorList.find(g => g.row === error.row);    
    if (group) {
        // if the row is already there
        group.data.push(error);
    } else {
        // if this is a new row
        accumulatorList.push({ row: error.row, data: [error] });
    }
    // remove row attribute from the error object
    delete error.row;

    
    return accumulatorList;
}, []);

console.log(errorGrouped);

CodePudding user response:

You can achieve this in a single loop by using hash (JS Object)

  • Hash will store the row index in the array so that you need not to look up again
  • once you have the index then you just need to access that array position to push the data

const errors = [
    {
        "row": 1,
        "key": "volume",
        "errorType": "Data type",
        "expectedType": "number",
        "receivedType": "string"
    },
    {
        "row": 1,
        "key": "units",
        "errorType": "Required data",
        "expectedType": "string"
    },
    {
        "row": 3,
        "key": "year",
        "errorType": "Incorrect data type",
        "expectedType": "number",
        "receivedType": "string"
    },
    {
        "row": 3,
        "key": "make",
        "errorType": "Required data",
        "expectedType": "string"
    }
];

const rowMapIndex = {};
const output = [];

for (let rowObj of errors) {
    const { row: rowID, ...restObj } = rowObj;

    let addAt = output.length;
    if (rowID in rowMapIndex)  {
        addAt = rowMapIndex[rowID];
    } else {
        rowMapIndex[rowID] = output.length;
        output.push({ row: rowID, data: [] });
    }
    output[addAt].data.push(restObj)
};

console.log(output);

  • Related