unnamed-bull
unnamed-bull

Reputation: 361

Javascript - reduce the given object into one data structure

I need to reduce the given object into some datastructure. This is my input object.

const receiver =  {
      USER1: {
        module: ['a_critical', 'a_normal','b_normal']
      },
      USER2: {
        module: ['a_critical', 'a_normal','b_critical']
      }, 
      USER3: {
        module: ['a_critical']
      }
    };

const allModules = ['a_normal', 'a_critical', 'b_normal', 'b_critical']; 

Desired output:

{
  "a_critical": [
    {
      "user": [
        "USER1", "USER2", "USER3"
      ]
    }
  ],
  "a_normal": [
    {
      "user": [
        "USER1", "USER2"
      ]
    }
 ],
  "b_normal": [
    {
      "user": [
        "USER1"
      ]
    }
  ],
  "b_critical": [
    {
      "user": [
        "USER2"
      ]
    }
  ]
} 

I have tried doing but i was getting some problems. I am getting some duplicate properties which should be there. I can share the code on what i have tried.

const receiverObj = {};

let count = 0;
Object.keys(receiver).forEach((item) => {
    receiver[item].module.forEach((module) => {
      if(allModules.includes(module)) {
        count  = 1;
        if(count) {
        receiverObj[module] = [];
           receiverObj[module].push({user: [item] });
        }
        receiverObj[module].push({user: item });
        count = 0;
      }
    })
});

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

Actual result which i got:

{
  "a_critical": [
    {
      "user": [
        "USER3"
      ]
    },
    {
      "user": "USER3"
    }
  ],
  "a_normal": [
    {
      "user": [
        "USER2"
      ]
    },
    {
      "user": "USER2"
    }
  ],
  "b_normal": [
    {
      "user": [
        "USER1"
      ]
    },
    {
      "user": "USER1"
    }
  ],
  "b_critical": [
    {
      "user": [
        "USER2"
      ]
    },
    {
      "user": "USER2"
    }
  ]
} 

Is there any optimal way of doing this ? can someone help ?

Upvotes: 5

Views: 81

Answers (5)

UtkarshPramodGupta
UtkarshPramodGupta

Reputation: 8152

Use Array.prototype.reduce()

const receiver = {
   USER1: {
     module: ['a_critical', 'a_normal','b_normal']
   },
   USER2: {
     module: ['a_critical', 'a_normal','b_critical']
   }, 
   USER3: {
     module: ['a_critical']
   }
}

const allModules = ['a_normal', 'a_critical', 'b_normal', 'b_critical']
 

const result = allModules.reduce((modulesObj, moduleName) => {
  modulesObj[moduleName] = [{ user: [] }]
  
  for (let user in receiver) {
    if (receiver[user].module.includes(moduleName)) {
      modulesObj[moduleName][0].user.push(user)
    }
  }
  
  return modulesObj
}, {})


console.log(result)

Upvotes: 1

Ponleu
Ponleu

Reputation: 1618

The below snippet reduce the provided allModules array into the expected result. However, I think this structure

"a_normal": {
      "user": [
        "USER1",
        "USER2"
      ]
 },
...

make sense more than the below snippet because you have to access the first index of each module to get user value

"a_normal": [
    {
      "user": [
        "USER1",
        "USER2"
      ]
    }
  ],

const receiver = {
  USER1: {  module: ["a_critical", "a_normal", "b_normal"] },
  USER2: { module: ["a_critical", "a_normal", "b_critical"] },
  USER3: {  module: ["a_critical"] }
};
const allModules = ["a_normal", "a_critical", "b_normal", "b_critical"]; 
const result = allModules.reduce((prevResult, curModule, index) => {
  if(!prevResult[curModule]) {
    prevResult[curModule]=[{user:[]}];
  }

  Object.keys(receiver).forEach((user) => {
    if(receiver[user].module.includes(curModule) &&
      !prevResult[curModule][0].user.includes(user)) {
        prevResult[curModule][0].user.push(user);
    }
  });

  return prevResult;
},{});
console.log(JSON.stringify(result, null, 2));

Upvotes: 0

Isaac Khoo
Isaac Khoo

Reputation: 545

const receiver = {
  USER1: {
    module: ["a_critical", "a_normal", "b_normal"]
  },
  USER2: {
    module: ["a_critical", "a_normal", "b_critical"]
  },
  USER3: {
    module: ["a_critical"]
  }
};

const allModules = ["a_normal", "a_critical", "b_normal", "b_critical"];

let reduce = () => {
  // create output object
  let output = {};

  // add modules into output
  allModules.map(mod => {
    return (output[mod] = [{ 'user': []}]);
  });

  // map users to modules
  for (let userKey in receiver) {
    let userModules = receiver[userKey].module;
    userModules.forEach(mod => {
      if(output.hasOwnProperty(mod)) {
        output[mod][0]['user'].push(userKey);
      }
    });
  }
};

reduce();

Straightforward way of getting the job done. No fancy functions used.Hopefully this logic would be easy to follow.

Upvotes: 0

Maksym Petrenko
Maksym Petrenko

Reputation: 1063

Try this one

const receiver =  {
      USER1: {
        module: ['a_critical', 'a_normal','b_normal']
      },
      USER2: {
        module: ['a_critical', 'a_normal','b_critical']
      }, 
      USER3: {
        module: ['a_critical']
      }
};

const userByModules = Object.keys(receiver).reduce(function (acc, user) {
	receiver[user].module.forEach((module) => {
		if (acc[module]) {
          acc[module].user.push(user);
        } else {
          acc[module] = {user: [user]};
        }
	});
    return acc;
}, {});

console.log(userByModules);

Upvotes: 0

CertainPerformance
CertainPerformance

Reputation: 371069

Iterate over each module in a reduce callback, creating a { user: [] } object in the accumulator if it doesn't exist yet, and then push to that array:

const receiver =  {
      USER1: {
        module: ['a_critical', 'a_normal','b_normal']
      },
      USER2: {
        module: ['a_critical', 'a_normal','b_critical']
      }, 
      USER3: {
        module: ['a_critical']
      }
    };

const output = Object.entries(receiver)
  .reduce((a, [user, { module }]) => {
    module.forEach((name) => {
      if (!a[name]) {
        a[name] = { user: [] };
      }
      a[name].user.push(user);
    });
    return a;
  }, {});
console.log(output);

You could also create the accumulator object in advance, if you wanted, since you have allModules, thereby avoiding conditionals inside the .reduce:

const receiver =  {
      USER1: {
        module: ['a_critical', 'a_normal','b_normal']
      },
      USER2: {
        module: ['a_critical', 'a_normal','b_critical']
      }, 
      USER3: {
        module: ['a_critical']
      }
    };

const allModules = ['a_normal', 'a_critical', 'b_normal', 'b_critical']; 
const accum = Object.fromEntries(
  allModules.map(
    name => [name, { user: [] }]
  )
);

const output = Object.entries(receiver)
  .reduce((a, [user, { module }]) => {
    module.forEach((name) => {
      a[name].user.push(user);
    });
    return a;
  }, accum);
console.log(output);

Upvotes: 4

Related Questions