Ways to categorize a collection of objects by their unique identifiers

Need help with grouping an array of objects within another array of objects based on id and code. Despite successful grouping by "id", struggling to achieve the same for the inner array of objects grouped by "code". Spent an entire day without any luck, any assistance would be greatly appreciated. Link to the Stackblitz is included.


    const result = this.data.reduce((a, c) => {
      const found = a.find(e => e.id === c.id);
      if (found) found.accessDetails[0].tcode.push(c.tcode);
      else a.push({
        groupId: c.groupId,
        id: c.id, accessDetails: [
          { code: c.code, tcode: [c.tcode] }
        ]
      });
      return a;
    }, []);
    console.log(result);
}

Input:


data = [{groupId: "111", id: "abc", code: "PPL", tcode: "Email"},
{groupId: "111", id: "abc", code: "PPL", tcode: "SMS"},
{groupId: "111", id: "abc", code: "PHL", tcode: "Email"},
{groupId: "111", id: "abc", code: "PHL", tcode: "Mobile"},
{groupId: "222", id: "def", code: "APL", tcode: "Letter"},
{groupId: "222", id: "def", code: "APL", tcode: "SMS"},
{groupId: "222", id: "def", code: "PPL", tcode: "Mobile"},
{groupId: "222", id: "def", code: "PHL", tcode: "Mobile"},
{groupId: "333", id: "ghi", code: "APL", tcode: "Letter"},
{groupId: "333", id: "ghi", code: "PHL", tcode: "SMS"}]

Expected Output:


[
    {
        "groupId": "111",
        "id": "abc",
        "accessDetails": [
            {
                "code": "PPL",
                "tcode": [
                    "Email"
                    "SMS"
                ]
            },
            {
                "code": "PPL",
                "tcode": [
                    "Email"
                    "Mobile"
                ]
            }
        ]
    },
    {
        "groupId": "222",
        "id": "def",
        "accessDetails": [
            {
                "code": "APL",
                "tcode": [
                    "Letter"
                    "SMS"
                ]
            },
            {
                "code": "PPL",
                "tcode": [
                    "Mobile"
                ]
            }
            {
                "code": "PHL",
                "tcode": [
                    "Mobile"
                ]
            }
        ]
    },
    {
        "groupId": "333",
        "id": "ghi",
        "accessDetails": [
            {
                "code": "APL",
                "tcode": [
                    "Letter"
                ]
            },
            {
                "code": "PHL",
                "tcode": [
                    "Email"
                    "SMS"
                ]
            }
        ]
    }
]

Link to Stackblitz

Answer №1

My preferred method involves maintaining objects keyed by unique IDs throughout the reduction process before utilizing Object.values(...) to streamline and extract arrays based on the outcome.

const data = [{groupId: "111", id: "abc", code: "PPL", tcode: "Email"},
{groupId: "111", id: "abc", code: "PPL", tcode: "SMS"},
{groupId: "111", id: "abc", code: "PHL", tcode: "Email"},
{groupId: "111", id: "abc", code: "PHL", tcode: "Mobile"},
{groupId: "222", id: "def", code: "APL", tcode: "Letter"},
{groupId: "222", id: "def", code: "APL", tcode: "SMS"},
{groupId: "222", id: "def", code: "PPL", tcode: "Mobile"},
{groupId: "222", id: "def", code: "PHL", tcode: "Mobile"},
{groupId: "333", id: "ghi", code: "APL", tcode: "Letter"},
{groupId: "333", id: "ghi", code: "PHL", tcode: "SMS"}];

const result = Object.values(data.reduce((a, c) => {
  a[c.id] = a[c.id] || {groupId: c.groupId, id: c.id, accessDetails: {}};
  a[c.id].accessDetails[c.code] = a[c.id].accessDetails[c.code] || {
    code: c.code,
    tcode: [],
  };
  a[c.id].accessDetails[c.code].tcode.push(c.tcode);
  return a;
}, {})).map(item => ({...item, accessDetails: Object.values(item.accessDetails)}));

console.log(result);

Answer №2

You might want to give this a shot

data = [{
    groupId: "111",
    id: "abc",
    code: "PPL",
    tcode: "Email"
  },
  {
    groupId: "111",
    id: "abc",
    code: "PPL",
    tcode: "SMS"
  },
  {
    groupId: "111",
    id: "abc",
    code: "PHL",
    tcode: "Email"
  },
  {
    groupId: "111",
    id: "abc",
    code: "PHL",
    tcode: "Mobile"
  },
  {
    groupId: "222",
    id: "def",
    code: "APL",
    tcode: "Letter"
  },
  {
    groupId: "222",
    id: "def",
    code: "APL",
    tcode: "SMS"
  },
  {
    groupId: "222",
    id: "def",
    code: "PPL",
    tcode: "Mobile"
  },
  {
    groupId: "222",
    id: "def",
    code: "PHL",
    tcode: "Mobile"
  },
  {
    groupId: "333",
    id: "ghi",
    code: "APL",
    tcode: "Letter"
  },
  {
    groupId: "333",
    id: "ghi",
    code: "PHL",
    tcode: "SMS"
  }
]


output = {}

data.forEach(val => {
  if (!output[val.groupId]) {
    output[val.groupId] = {
      groupId: val.groupId,
      id: val.id,
      accessDetails: [{
        code: val.code,
        tcode: [val.tcode]
      }]
    };
  } else {
    const foundIndex = output[val.groupId].accessDetails.findIndex(({ 
      code
    }) => code === val.code);
    if (foundIndex !== -1) {
      output[val.groupId].accessDetails[foundIndex].tcode.push(val.tcode)
    } else {
      output[val.groupId].accessDetails.push({
        code: val.code,
        tcode: [val.tcode]
      });

    }

  }

})

console.info(Object.values(output));

Answer №3

perhaps this solution could be of assistance to you.

    const data = [{ groupId: "111", id: "abc", code: "PPL", tcode: "Email" },
    { groupId: "111", id: "abc", code: "PPL", tcode: "SMS" },
    { groupId: "111", id: "abc", code: "PHL", tcode: "Email" },
    { groupId: "111", id: "abc", code: "PHL", tcode: "Mobile" },
    { groupId: "222", id: "def", code: "APL", tcode: "Letter" },
    { groupId: "222", id: "def", code: "APL", tcode: "SMS" },
    { groupId: "222", id: "def", code: "PPL", tcode: "Mobile" },
    { groupId: "222", id: "def", code: "PHL", tcode: "Mobile" },
    { groupId: "333", id: "ghi", code: "APL", tcode: "Letter" },
    { groupId: "333", id: "ghi", code: "PHL", tcode: "SMS" }];

    const tracker = {};
    const result = data.reduce((acc, cur) => {
        let found = tracker[cur.groupId];
        if (!found) {
            found = {
                groupId: cur.groupId,
                id: cur.id,
                accessDetails: [],
            };
            tracker[cur.groupId] = found;
            acc.push(found);
        }

        let details = found.accessDetails.find(x => x.code === cur.code);
        if (!details) {
            details = {
                code: cur.code,
                tcode: []
            };
            found.accessDetails.push(details);
        }
        details.tcode.push(cur.tcode);
        return acc;
    }, []);

    console.log(JSON.stringify(result, null, 2));

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

JavaScript - Assigning a class to an element based on an array

I am facing a challenge where I need to assign classes from an array to an element in sequential order. The issue is that once I reach the end of the array, I do not know how to loop back to the beginning and start over. Here is my current code: var bac ...

Deploying Angular to a shared drive can be done in a

My angular.json file contains the following line: "outputPath": "Y:\Sites\MySite", After running ng build, I encountered the error message: An unhandled exception occurred: ENOENT: no such file or directory, mkdir 'D:& ...

Exploring the Concept of Angular4 Component Nesting and Input Issues

I've taken on the challenge of completing an exercise from the book "Angular From Theory To Practice - Asim Hussain". The exercise involves refactoring an app using Angular CLI instead of having all components in the same file. You can find a sample f ...

Saving incoming text files from a client via a websocket connection: A step-by-step guide

I've been working on creating a websocket server in node.js from scratch, without relying on any frameworks. So far, I have successfully set up the messages to be sent from the client to the server. However, I recently encountered an issue when trying ...

Prevent any YouTube iframe from playing when a different one is activated

I have a unique challenge where I need to embed 10 YouTube iframes in my webpage, each with its own custom play/pause buttons. While I started with this solution from http://jsfiddle.net/buuuue/dzroqgj0/, I am struggling to modify the code to ensure that w ...

Optimal approach for verifying the POST request payload

My RESTful API has a POST endpoint for user creation, and I am looking to implement data validation before inserting it into the database. There are two approaches I'm considering: Approach 1: Incorporating model validation in the controller and repe ...

What is the process of assigning an id property to mat-select?

Can you assign an id to a mat-select element? I attempted to do this with the following code: <mat-select id="mat-select-{{example.id}}"> <mat-option *ngFor="let u of users" [value]="u.id"> {{u.name}} </mat-option> </ ...

The issue of overflow-y not functioning properly in conjunction with ng-repeat has been observed

As indicated in this resource, setting a fixed height for the div is suggested, but it seems like it's not working with the code provided below. <div style="margin-top:0.5vh;"> <div style="height:200px;border:1px solid red;overflow:au ...

Compiling a TypeScript project to generate the correct index.js file is currently not successfully completed

Looking to set up the TypeScript project here. The steps are: git clone https://github.com/simpleledger/BitcoinFilesJS.git test/ cd test npm i tsc # or npx tsc The resulting index.js is shown below: "use strict"; var __createBinding = (this & ...

I'm experiencing some challenges with setting up my sequelize relationships

After tirelessly searching for a solution to my problem and coming up empty-handed, I decided to reach out here. Every Google search result seems unhelpful and every link I click on is disappointingly pink. Hello everyone! I'm facing difficulties est ...

Troubleshooting problems with production builds in Angular 5 using Node.js Express

Encountered a problem while attempting to create a production build of my angular and node.js project. Running the angular project with ng serve and backend with nodemon server works fine. However, after running ng build --prod and modifying the backend to ...

TypeError occurs when app.use is used with multer configuration

I am currently facing an issue while attempting to set up multer in my app.js file (using node.js/express) for enabling users to upload images. The code snippet in app.js is as follows: // Various require statements including passport, cookie parser, etc. ...

When a service alias is provided in Angular 7, it disrupts the build execution process

After creating a service called MyService and its mocked version - MyServiceMock, I utilized the mock service in my unit tests until the backend is ready, providing and using the results from the mocked service. To avoid future code changes when the backe ...

Creating a dynamic JPanel with jQuery: A step-by-step guide

While attempting to utilize jPanel for a collapsible panel generated dynamically from an XML content, I encountered an issue where the dynamically created panels were not appearing as expected. Refer to the image below: Here is my container: <div id=" ...

Omit specific TagNames from the selection

How can I exclude <BR> elements when using the statement below? var children = document.getElementById('id').getElementsByTagName('*'); Is there a special syntax for getElementsByTagName that allows me to achieve this, or is the ...

If I remove my project but still have it saved on my GitHub, do I need to reinstall all the dependencies or can I simply run npm install again?

I have a question regarding my deleted project that is saved on GitHub. If I formatted my PC and lost the project but it's still on GitHub, do I need to reinstall all the dependencies or can I just run 'npm install'? The project has dependen ...

What is the best way to calculate the total of all files within a folder structure using JavaScript

Here is the array I'm working with: Array (7812) 0 {foldername: "", amount_of_files: 12, children: 86} 1 {foldername: "/pm", amount_of_files: 3, children: 7} 2 {foldername: "/pm/css", amount_of_files: 1, children: 0} 3 {f ...

JavaScript - Populate canvas with selected image from gallery upon clicking an image

A photo gallery on my website is filled with images fetched from a local directory using PHP. I would like users to be able to select an image by clicking on it and then have the option to draw on that image within a canvas element. The gallery has been c ...

Encountering problem when trying to upload several images at once using a single input in CodeIgniter with

I'm attempting to use CodeIgniter and AJAX to upload multiple images using a single input field. Here's the code I have so far: HTML: <input type="file" name="files[]" id="file" multiple /> AJAX: $("#addItems").on("submit",function(e) { ...

Discovering the Vue app container div attribute

I am currently working on a Java app that generates pages server-side based on certain data, such as a publisher for a specific entity. I want to develop a reusable Vue component that can call an API method to request data about the entity that is being vi ...