Группировать по lastName и переменной firstName

Пытаюсь решить проблему, как сгруппировать именные объекты. Имя имеет свойства firstName и lastName. Необходимо сгруппировать объекты имени с одинаковыми фамилиями и похожим firstName (также известные как Том Смит и Томас Смит должны быть сгруппированы вместе). Случай не имеет значения. Эквивалентность firstName обеспечивается строкой, разделенной знаками «;».

пример:

Вход:

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" },
];

выход:

[
    [
      { 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' } ]
]

Вот что у меня есть сейчас:

const groupDuplicates = (list, dictionary) => {
  const mappedNames = mapDictionary(dictionary);
  const groupByNames = {};
  people.forEach((person) => {
    // 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 "[1, smith]"

    // 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) => {
    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) => {
  const nameGroups = dictionary.split(";");
  let nameKey = 1;
  const mapNameToKey = {};
  nameGroups.forEach((nameGroup) => {
    const names = nameGroup.split(",");
    names.forEach((name) => {
      const noSpacesAndLowercase = name.trim().toLowerCase();
      mapNameToKey[noSpacesAndLowercase] = nameKey;
    });
    nameKey += 1;
  });
  return mapNameToKey;
};

Кажется, работает, но есть ли лучший способ добиться этого? я думаю JSON.stringify кажется немного взломанным.

1 ответ
1

Если у вас есть простой groupBy функция и группировка по строке key с форматом [lastName]|[firstNameKey or firstName], было бы чище. Вот моя версия кода:

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

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

const groupDuplicate = (people, dictionary) => {
  return Object.values(groupBy(people, (person) => `${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)

    Добавить комментарий

    Ваш адрес email не будет опубликован. Обязательные поля помечены *