Underscore/lodash уникальный по нескольким свойствам
У меня есть массив объектов с дубликатами, и я пытаюсь получить уникальный список, где уникальность определяется подмножеством свойств объекта. Например,
{a:"1",b:"1",c:"2"}
И я хочу игнорировать c
в сравнении уникальности.
Я могу сделать что-то вроде
_.uniq(myArray,function(element) { return element.a + "_" + element+b});
Я надеялся, что смогу сделать
_.uniq(myArray,function(element) { return {a:element.a, b:element.b} });
Но это не работает. Есть ли что-то подобное, что я могу сделать, или мне нужно создать сопоставимое представление объекта, если я сравниваю несколько свойств?
Ответы
Ответ 1
Похоже, что нет простого способа сделать это, к сожалению. Если вы не написали свою собственную функцию для этого, вам нужно будет вернуть что-то, что можно напрямую сравнить для равенства (как в первом примере).
Один из методов - просто .join()
необходимые вам свойства:
_.uniqBy(myArray, function(elem) { return [elem.a, elem.b].join(); });
В качестве альтернативы вы можете использовать _.pick
или _.omit
, чтобы удалить все, что вы не делаете необходимость. Оттуда вы можете использовать _.values
с .join()
или даже просто JSON.stringify
:
_.uniqBy(myArray, function(elem) {
return JSON.stringify(_.pick(elem, ['a', 'b']));
});
Имейте в виду, что объекты не детерминированы, поскольку порядок свойств идет, поэтому вы можете просто придерживаться метода явного массива.
P.S. Замените uniqBy
на uniq
для Lodash < 4
Ответ 2
Я действительно думаю, что метод join() по-прежнему является самым простым. Несмотря на проблемы, поднятые в предыдущем решении, я думаю, что выбор правильного разделителя является ключом к предотвращению выявленных ошибок (с разными наборами значений, возвращающими одно и то же значение). Имейте в виду, что разделитель не должен быть единственным символом, это может быть любая строка, которая, как вы уверены, не будет происходить естественным образом в самих данных. Я делаю это все время и люблю использовать '~! $~' В качестве моего разделителя. Он также может включать специальные символы, такие как \t\r\n и т.д.
Если содержащиеся данные действительно непредсказуемы, возможно, максимальная длина известна, и вы можете просто проложить каждый элемент до максимальной длины до присоединения.
Ответ 3
Используйте метод Lodash uniqWith
:
_.uniqWith(array, [comparator])
Этот метод похож на _.uniq
за исключением того, что он принимает comparator
который вызывается для сравнения элементов array
. Порядок значений результатов определяется порядком их появления в массиве. Компаратор вызывается с двумя аргументами: (arrVal, othVal).
Когда comparator
возвращает true
, элементы считаются дубликатами, и только новое вхождение будет включено в новый массив.
Пример:
У меня есть список местоположений с latitude
и longitude
- некоторые из которых идентичны - и я хочу увидеть список уникальных мест:
const locations = [
{
name: "Office 1",
latitude: -30,
longitude: -30
},
{
name: "Office 2",
latitude: -30,
longitude: 10
},
{
name: "Office 3",
latitude: -30,
longitude: 10
}
];
const uniqueLocations = _.uniqWith(
locations,
(locationA, locationB) =>
locationA.latitude === locationB.latitude &&
locationA.longitude === locationB.longitude
);
// Result has Office 1 and Office 2
Ответ 4
В совмещенном ответе @voithos и @Danail есть подсказка. Я решил, как это добавить уникальный ключ к объектам в моем массиве.
Начальные данные образца
const animalArray = [
{ a: 4, b: 'cat', d: 'generic' },
{ a: 5, b: 'cat', d: 'generic' },
{ a: 4, b: 'dog', d: 'generic' },
{ a: 4, b: 'cat', d: 'generic' },
];
В приведенном выше примере я хочу, чтобы массив был уникальным для a
и b
но сейчас у меня есть два объекта, которые имеют a: 4
и b: 'cat'
. Объединяя + b в строку, я могу получить уникальный ключ для проверки.
{ a: 4, b: 'cat', d: 'generic', id: '${a}-${b}' }. // id is now '4-cat'
Примечание. Очевидно, что вам необходимо отобразить данные или сделать это при создании объекта, поскольку вы не можете ссылаться на свойства объекта в пределах одного и того же объекта.
Теперь сравнение простое...
_.uniqBy(animalArray, 'id');
Полученный массив будет длиной 3, в нем будет удален последний дубликат.