Group by lastName and variable firstName I'm trying to solve a problem of how to group name objects. A name has firstName and lastName properties. Need to group the name objects that have identical lastnames and a similar firstName(aka Tom Smith and Thomas Smith should be grouped together). Case doesn't matter. The firstName equivalency is provided by a string separated by &quot;;&quot;'s.
example:
input:
const FIRST_NAME_DICTIONARY =
  &quot;Robert, Bob, Bobby; Liz, Elizabeth, Beth; Tom, Thomas&quot;;

const people = [
  { firstName: &quot;robert&quot;, lastName: &quot;smith&quot; },
  { firstName: &quot;Liz&quot;, lastName: &quot;thomas&quot; },
  { firstName: &quot;robert&quot;, lastName: &quot;smith&quot; },
  { firstName: &quot;Thomas&quot;, lastName: &quot;hardin&quot; },
  { firstName: &quot;Elizabeth&quot;, lastName: &quot;thomas&quot; },
  { firstName: &quot;bob&quot;, lastName: &quot;smith&quot; },
  { firstName: &quot;Bobby&quot;, lastName: &quot;smith&quot; },
  { firstName: &quot;ryan&quot;, lastName: &quot;roberts&quot; },
  { firstName: &quot;bob&quot;, lastName: &quot;wallace&quot; },
  { firstName: &quot;bobby&quot;, lastName: &quot;smith&quot; },
  { firstName: &quot;beth&quot;, lastName: &quot;roberts&quot; },
  { firstName: &quot;beth&quot;, lastName: &quot;thomas&quot; },
  { firstName: &quot;Tom&quot;, lastName: &quot;hardin&quot; },
];

output:
[
    [
      { firstName: 'robert', lastName: 'smith' },
      { firstName: 'robert', lastName: 'smith' },
      { firstName: 'bob', lastName: 'smith' },
      { firstName: 'Bobby', lastName: 'smith' },
      { firstName: 'bobby', lastName: 'smith' }
    ],
    [
      { firstName: 'Liz', lastName: 'thomas' },
      { firstName: 'Elizabeth', lastName: 'thomas' },
      { firstName: 'beth', lastName: 'thomas' }
    ],
    [
      { firstName: 'Thomas', lastName: 'hardin' },
      { firstName: 'Tom', lastName: 'hardin' }
    ],
    [ { firstName: 'ryan', lastName: 'roberts' } ],
    [ { firstName: 'bob', lastName: 'wallace' } ],
    [ { firstName: 'beth', lastName: 'roberts' } ]
]

Here's what I have now:
const groupDuplicates = (list, dictionary) =&gt; {
  const mappedNames = mapDictionary(dictionary);
  const groupByNames = {};
  people.forEach((person) =&gt; {
    // gets the id equivalent for firstName or use the firstName it the id DNE
    const firstNameId =
      mappedNames[person?.firstName?.toLowerCase()] ||
      person?.firstName.toLowerCase(); // example 1 or ryan since ryan dne in the dictionary
    const stringifyKey = JSON.stringify([
      firstNameId,
      person.lastName.toLowerCase(),
    ]); // example &quot;[1, smith]&quot;

    // if key exists push to that array, otherwise create the key and then push
    if (groupByNames[stringifyKey]) {
      groupByNames[stringifyKey].push(person);
    } else {
      groupByNames[stringifyKey] = [person];
    }
  });

  // essentially convert object into array
  const keys = Object.keys(groupByNames);
  const groupByNamesArray = [];
  keys.forEach((key) =&gt; {
    groupByNamesArray.push(groupByNames[key]);
  });

  return groupByNamesArray;
};

// {
//     robert: 1,
//     bob: 1,
//     bobby: 1,
//     liz: 2,
//     elizabeth: 2,
//     beth: 2,
//     tom: 3,
//     thomas: 3
// }
const mapDictionary = (dictionary) =&gt; {
  const nameGroups = dictionary.split(&quot;;&quot;);
  let nameKey = 1;
  const mapNameToKey = {};
  nameGroups.forEach((nameGroup) =&gt; {
    const names = nameGroup.split(&quot;,&quot;);
    names.forEach((name) =&gt; {
      const noSpacesAndLowercase = name.trim().toLowerCase();
      mapNameToKey[noSpacesAndLowercase] = nameKey;
    });
    nameKey += 1;
  });
  return mapNameToKey;
};

Seems to work but is there a better way to accomplish this? I think the JSON.stringify seems a little hacky.
If you have a simple groupBy function, and group by a string key with format [lastName]|[firstNameKey or firstName], it'd be cleaner. The following is my version of the code:


// FUNCTIONS
const groupBy = (list, key) =&gt; {
  return list.reduce((current, value) =&gt; {
    (current[key(value)] = current[key(value)] || []).push(value);
    return current;
  }, {});
};

const mapDictionary =
  (str) =&gt; str
  .split(';')
  .map((val, idx) =&gt; {
    return {
      grp: idx + 1,
      val: val
    };
  })
  .reduce((current, group) =&gt; {
    const groupResult = group.val
      .split(',').reduce((gr, name) =&gt; {
        gr[name.trim().toLowerCase()] = group.grp;
        return gr;
      }, {});
    return {
      ...current,
      ...groupResult
    };
  }, {});

const groupDuplicate = (people, dictionary) =&gt; {
  return Object.values(groupBy(people, (person) =&gt; `${person.lastName}|${dictionary[person.firstName.toLowerCase()] || person.firstName}`));
};


// TEST CASE
const FIRST_NAME_DICTIONARY =
  "Robert, Bob, Bobby; Liz, Elizabeth, Beth; Tom, Thomas";

const people = [{
    firstName: "robert",
    lastName: "smith"
  },
  {
    firstName: "Liz",
    lastName: "thomas"
  },
  {
    firstName: "robert",
    lastName: "smith"
  },
  {
    firstName: "Thomas",
    lastName: "hardin"
  },
  {
    firstName: "Elizabeth",
    lastName: "thomas"
  },
  {
    firstName: "bob",
    lastName: "smith"
  },
  {
    firstName: "Bobby",
    lastName: "smith"
  },
  {
    firstName: "ryan",
    lastName: "roberts"
  },
  {
    firstName: "bob",
    lastName: "wallace"
  },
  {
    firstName: "bobby",
    lastName: "smith"
  },
  {
    firstName: "beth",
    lastName: "roberts"
  },
  {
    firstName: "beth",
    lastName: "thomas"
  },
  {
    firstName: "Tom",
    lastName: "hardin"
  },
];

const result = groupDuplicate(people, mapDictionary(FIRST_NAME_DICTIONARY));

// PRINT RESULT
console.log(result)