3

I have been trying to work on an array which should returns an object with the object structure where the key is acctName and value is an array of firstName+ lastName

const employees = [
            { acctName: "Sogeti", firstName: "Sam", lastName: "Smith" },
            { acctName: "GE", firstName: "Daniel", lastName: "Kroger" },
            { acctName: "Sogeti", firstName: "Derek", lastName: "Keen" },
            { acctName: "Universal", firstName: "Sam", lastName: "Sood" },
            { acctName: "Universal", firstName: "Andy", lastName: "Williams" },
            { acctName: "Sogeti", firstName: "Jessica", lastName: "Arvello" },
            { acctName: "GE", firstName: "Kelly", lastName: "Saffer" },
            { acctName: "Universal", firstName: "Hector", lastName: "Fernandez" },
          ];

Expected Output :

var rturnObject = {
        "Sogeti": ["Sam Smith", "Derek Keen", "Jessica Arvello"],
        "Universal": ["Sam Sood", "Andy Williams", "Hector Fernandez"],
        "GE": ["Daniel Krogger", "Kelly Saffer"],
      };

I can loop through object array and push the new updated record to the array but is there any efficient way to solve this?

1
  • 3
    fyi: This type of questions is better suited for Stackoverflow, as it is not related to Salesforce (simple javascript)
    – glls
    Nov 30 '21 at 12:46
9

You can do this mapping with a "one-liner":

const returnValue = employees.reduce((p,v) => (p[v.acctName] = [...(p[v.acctName] || []), `${v.firstName} ${v.lastName}`], p), {})

Where:

  • `${v.firstName} ${v.lastName}` is used to construct firstName + ' ' + lastName via a Template Literal
  • (p[v.acctName] || []) is used to use the existing array, or a new one if the there is none, using the Shortcut Or operator
  • [...x, y] uses the spread operator ... to copy the array x (from the previous explanation above) and add a new element y to that new array
  • (x, y), the comma operator, is used to evaluate x and then return y; we evaluate p[v.acctName] [...(p[v.acctName] || []), `${v.firstName} ${v.lastName}`], then return p, which is required for Array.prototype.reduce to work properly
  • (p,v) => (...) is an arrow function; we use parentheses to tell JavaScript that the contents are a return value, not a function block, and also to make sure that the comma operator isn't interpreted as a separate parameter for Array.prototype.reduce rather than part of the Arrow function
  • Array.prototype.reduce is used to collapse many values into one; here, we use it to collapse the list using the function (p,v) => (p[v.acctName] = [...(p[v.acctName] || []), `${v.firstName} ${v.lastName}`], p) into the value {} (a new Object)

This answer is more of a "here's some really cool things you can do in JavaScript", and while some developers might prefer this style, the other answers are probably better in performance and legibility. You can reformat this code to read:

const returnObject = employees.reduce(
  (p, v) => (
    (p[v.acctName] = [ // Assign array to p[v.acctName]
      ...(p[v.acctName] || []), // copy old array or make a new array
      `${v.firstName} ${v.lastName}`, // template literal
    ]),
    p // returns p for next Array.prototype.reduce call
  ),
  {} // Object to be populated by acctName: [...names]
);

Edit:

After playing with performance a bit, I came up with:

const returnValue = employees.reduce((p, { acctName, firstName, lastName }) => {
  const name = firstName + " " + lastName, values = p.get(acctName) || [];
  values.push(name);
  values.length == 1 && p.set(acctName, values);
  return p;
}, new Map());

Which now ranks 11% faster than the Nagendra's solution, and 24% better than Phil's, while still being relatively concise. I'd like to take a moment to thank both of them for teaching me some stuff about performance today.

This answer is more of a "there are many ways to do the same thing in JS" anyways, just another set of alternatives to work with.

2
  • 2
    This is amazing. This looks like a minified version of my solution. Nov 30 '21 at 18:46
  • @NagendraSingh It basically is, I just added destructuring and optimized the if statement to try to squeeze out a bit more performance, and it happened to work. Thanks again for the inspiration.
    – sfdcfox
    Dec 1 '21 at 2:25
5

I can't think of a more efficient way to do this than what you suggest:

const returnObject = {};

employees.forEach(employee => {
  const fullName = employee.firstName + ' ' + employee.lastName;

  if (returnObject[employee.acctName]) {
    returnObject[employee.acctName].push(fullName);
  } else {
    returnObject[employee.acctName] = [fullName];
  }
});
5

You can use ES6 reduce method to fetch the required Map this:

  employees1.reduce((mapAccumulator, obj) => {
    let innerList = [];
    if(mapAccumulator.get(obj.acctName) === undefined){
      innerList.push(obj.firstName + ' ' + obj.lastName);
      mapAccumulator.set(obj.acctName, innerList);
    } else {
      mapAccumulator.get(obj.acctName).push(obj.firstName + ' ' + obj.lastName);
    }
  
    return mapAccumulator;
  }, new Map());
8
  • This approach (having repeatedly looped both approaches 1000000 times each) does seem to be a smidge faster than my solution, at least in Chrome. I would argue that it is a little more cryptic though :)
    – Phil W
    Nov 30 '21 at 10:37
  • Tried the same with few millions, and saw the same result. I agree this to be cryptic if someone is not familiar with ES6 functions. Nov 30 '21 at 11:32
  • 1
    @sfdcfox, your solution runs about 40% slower than mine, and about 50% slower than Nagendra's. Rough figures only.
    – Phil W
    Nov 30 '21 at 17:26
  • 2
    @PhilW That's kind of what I suspected. I'm good at utilizing many of the language features of JS, but not so good at knowing which new features are better/worse for performance. I'll have to experiment sometime.
    – sfdcfox
    Nov 30 '21 at 17:32
  • 2
    @PhilW Thanks for the inspiration, by the way. I just found an algorithm that's faster than this by 11%, and yours by 24%. I've learned something new today about JS performance. See my edit, you might learn something, too.
    – sfdcfox
    Nov 30 '21 at 18:05

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.