0

Given an array of object

const data = [ 
  { id: 1,
    documentation_id: 4,
    document_id: 'nil',
    category_id: 1,
    created_at: "2020-03-29T11:06:44.000Z",
    updated_at: "2020-03-29T11:06:44.000Z" },
  { id: 11,
    documentation_id: 10,
    document_id: 'nil',
    category_id: 1,
    created_at: "2020-03-29T11:06:44.000Z",
    updated_at: "2020-03-29T11:06:44.000Z" },
  { id: 2,
    documentation_id: 5,
    document_id: '1',
    category_id: 2,
    created_at: "2020-03-29T11:06:44.000Z",
    updated_at: "2020-03-29T11:06:44.000Z" },
  { id: 100,
    documentation_id: 15,
    document_id: '10',
    category_id: 2,
    created_at: "2020-03-29T11:06:44.000Z",
    updated_at: "2020-03-29T11:06:44.000Z" },
  { id: 3,
    documentation_id: 5,
    document_id: '3',
    category_id: 3,
    created_at: "2020-03-29T11:06:44.000Z",
    updated_at: "2020-03-29T11:06:44.000Z" },
  { id: 4,
    documentation_id: 6,
    document_id: '1',
    category_id: 4,
    created_at: "2020-03-29T11:06:44.000Z",
    updated_at: "2020-03-29T11:06:44.000Z" },
  { id: 5,
    documentation_id: 6,
    document_id: '3',
    category_id: 5,
    created_at: "2020-03-29T11:06:44.000Z",
    updated_at: "2020-03-29T11:06:44.000Z" },
  { id: 6,
    documentation_id: 6,
    document_id: '5',
    category_id: 1,
    created_at: "2020-03-29T11:06:44.000Z",
    updated_at: "2020-03-29T11:06:44.000Z" 
  },
  { id: 7,
    documentation_id: 7,
    document_id: '1',
    category_id: 6,
    created_at: "2020-03-29T11:06:44.000Z",
    updated_at: "2020-03-29T11:06:44.000Z"}]

I want to be able to group by category_id such that result looks like this

const data = [{
    category_id: 1,
    documentation: [{
        document_id: "nil",
        documentation_id: 4
    }, {
        document_id: "nil",
        documentation_id: 10
    }, {
        document_id: "5",
        documentation_id: 6
    }]
}, {
    category_id: 2,
    documentation: [{
        document_id: "1",
        documentation_id: 5
    }, {
        document_id: "10",
        documentation_id: 15
    }]
}, {
    category_id: 3,
    documentation: [{
        document_id: "3",
        documentation_id: 5
    }]
}, {
    category_id: 4,
    documentation: [{
        document_id: "1",
        documentation_id: 6
    }]
}, {
    category_id: 5,
    documentation: [{
        document_id: "3",
        documentation_id: 6
    }]
}, {
    category_id: 6,
    documentation: [{
        document_id: "1",
        documentation_id: 7
    }]
}]

if the category exists more than once, create a documentation array and push the documentation in that category into the array. If the category exists once then push the only documentation for that category into the array.

This is the inefficient solution I came up with. I want to optimize the solution

function groupDocumentationByCategory(data) {
    const result = [];
    const formattedArray = data.slice(0);
    const seen = [];
    for (let k = 0; k < data.length; k++) {
        if (seen.indexOf(data[k].category_id) < 0) {
            seen.push(data[k].category_id);
            formattedArray[k].documentation = [];
            for (let j = 0; j < formattedArray.length; j++) {
                if (data[k].category_id === data[j].category_id) {
                    formattedArray[k].documentation.push({
                        document_id: formattedArray[j].document_id,
                        documentation_id: formattedArray[j].documentation_id,
                    });
                    delete data[k].documentation_id;
                    delete data[k].document_id;
                    delete data[k].created_at;
                    delete data[k].updated_at;
                }
            }
            result.push(data[k]);
        }
    }
    return result;
}

2 Answers 2

1

Iterate over the array and construct an object indexed by category_id. The first time an category_id is found, create the id and category_id properties, and initialize the documentation property to the empty array. Then push to that array. At the end, take the object's values:

const data=[{id:1,documentation_id:4,document_id:"nil",category_id:1,created_at:"2020-03-29T11:06:44.000Z",updated_at:"2020-03-29T11:06:44.000Z"},{id:11,documentation_id:10,document_id:"nil",category_id:1,created_at:"2020-03-29T11:06:44.000Z",updated_at:"2020-03-29T11:06:44.000Z"},{id:2,documentation_id:5,document_id:"1",category_id:2,created_at:"2020-03-29T11:06:44.000Z",updated_at:"2020-03-29T11:06:44.000Z"},{id:100,documentation_id:15,document_id:"10",category_id:2,created_at:"2020-03-29T11:06:44.000Z",updated_at:"2020-03-29T11:06:44.000Z"},{id:3,documentation_id:5,document_id:"3",category_id:3,created_at:"2020-03-29T11:06:44.000Z",updated_at:"2020-03-29T11:06:44.000Z"},{id:4,documentation_id:6,document_id:"1",category_id:4,created_at:"2020-03-29T11:06:44.000Z",updated_at:"2020-03-29T11:06:44.000Z"},{id:5,documentation_id:6,document_id:"3",category_id:5,created_at:"2020-03-29T11:06:44.000Z",updated_at:"2020-03-29T11:06:44.000Z"},{id:6,documentation_id:6,document_id:"5",category_id:1,created_at:"2020-03-29T11:06:44.000Z",updated_at:"2020-03-29T11:06:44.000Z"},{id:7,documentation_id:7,document_id:"1",category_id:6,created_at:"2020-03-29T11:06:44.000Z",updated_at:"2020-03-29T11:06:44.000Z"}];

const dataByCategory = {};
for (const { id, category_id, document_id, documentation_id } of data) {
  if (!dataByCategory[category_id]) {
    dataByCategory[category_id] = {
      id,
      category_id,
      documentation: []
    };
  }
  dataByCategory[category_id].documentation.push({ document_id, documentation_id });
}

console.log(Object.values(dataByCategory));

Sign up to request clarification or add additional context in comments.

2 Comments

What is the run time of this algorithm if I may ask. 0(n) ?
Yes, it's just a plain iteration through all elements of the original array, O(n)
1

You can use Array.prototype.reduce combined with some Array.prototype.map to achieve the result.

Maybe it can help.

var data = [{
    id: 1,
    documentation_id: 4,
    document_id: "nil",
    category_id: 1,
    created_at: "2020-03-29T11:06:44.000Z",
    updated_at: "2020-03-29T11:06:44.000Z"
  },
  {
    id: 11,
    documentation_id: 10,
    document_id: "nil",
    category_id: 1,
    created_at: "2020-03-29T11:06:44.000Z",
    updated_at: "2020-03-29T11:06:44.000Z"
  },
  {
    id: 2,
    documentation_id: 5,
    document_id: "1",
    category_id: 2,
    created_at: "2020-03-29T11:06:44.000Z",
    updated_at: "2020-03-29T11:06:44.000Z"
  },
  {
    id: 100,
    documentation_id: 15,
    document_id: "10",
    category_id: 2,
    created_at: "2020-03-29T11:06:44.000Z",
    updated_at: "2020-03-29T11:06:44.000Z"
  },
  {
    id: 3,
    documentation_id: 5,
    document_id: "3",
    category_id: 3,
    created_at: "2020-03-29T11:06:44.000Z",
    updated_at: "2020-03-29T11:06:44.000Z"
  },
  {
    id: 4,
    documentation_id: 6,
    document_id: "1",
    category_id: 4,
    created_at: "2020-03-29T11:06:44.000Z",
    updated_at: "2020-03-29T11:06:44.000Z"
  },
  {
    id: 5,
    documentation_id: 6,
    document_id: "3",
    category_id: 5,
    created_at: "2020-03-29T11:06:44.000Z",
    updated_at: "2020-03-29T11:06:44.000Z"
  },
  {
    id: 6,
    documentation_id: 6,
    document_id: "5",
    category_id: 1,
    created_at: "2020-03-29T11:06:44.000Z",
    updated_at: "2020-03-29T11:06:44.000Z"
  },
  {
    id: 7,
    documentation_id: 7,
    document_id: "1",
    category_id: 6,
    created_at: "2020-03-29T11:06:44.000Z",
    updated_at: "2020-03-29T11:06:44.000Z"
  }
];

data = data.reduce((acc, val) => {
  if (acc[val.category_id]) {
    acc[val.category_id].push(val);
  } else {
    acc[val.category_id] = [val];
  }

  return acc;
}, {});

data = Object.values(data)
  .map(val => {
    delete val.created_at;
    delete val.updated_at;
    return val;
  })
  .reduce((acc, val) => {
    let documentation = val.map(v => ({
      document_id: v.document_id,
      documentation_id: v.documentation_id
    }));
    acc.push({
      category_id: val[0].category_id,
      documentation
    });
    return acc;
  }, []);

console.log(data);

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.