Пытаюсь решить проблему, как сгруппировать именные объекты. Имя имеет свойства 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 ответ
Если у вас есть простой 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)