JS - фильтрует массив объектов на наличие дубликатов одного свойства и решает, какой объект сохранить, основываясь на другом свойстве - PullRequest
0 голосов
/ 29 октября 2018

Попытка отфильтровать массив объектов путем исключения объектов, у которых есть определенное свойство, которое уже существует в другом объекте (дубликат). Решение, какой объект удалить, должно основываться на другом свойстве.

Пример: Для массива объектов, который может выглядеть следующим образом, цель состоит в том, чтобы отфильтровать все «пользовательские» дубликаты и сохранить один с самым старым свойством «date».

const arr = [
    {user: 'Alex', date: '1540801929945'},
    {user: 'Bill', date: '1640801929946'},
    {user: 'Carl', date: '1740801929947'},
    {user: 'Alex', date: '1840801929948'},
]

Ожидаемый результат:

filteredArr = [
    {user: 'Alex', date: '1540801929945'},
    {user: 'Bill', date: '1640801929946'},
    {user: 'Carl', date: '1740801929947'},
]

Я управлял базовой фильтрацией, которая работает только для хранения уникальных объектов.

const filteredArr = arr.reduce((unique, o) => {
    if(!unique.some(obj => obj.user === o.user) {
      unique.push(o);
    }
    return unique;
},[]);

Хотя я не могу понять, что делать, чтобы в случае дубликата «самый старый» объект оставался, а самый последний удалялся. Большое спасибо за Вашу помощь! Очень ценят.

Ответы [ 4 ]

0 голосов
/ 29 октября 2018

Полагаю, вам действительно нужно знать индекс неуникального элемента (в вашем случае объект с именем "Alex"), а затем сравнивать их даты, сохраняя более старый.

Array.prototype.find не поможет вам в этом случае. Тем не менее, Array.prototype.find может быть полезен, поскольку он принимает обратный вызов, который возвращает логическое значение (точно так же, как 'some'), НО он возвращает индекс элемента, соответствующего вашему обратному вызову, или неопределенный, если такой элемент не найден.

Попробуйте, это не больно:)

0 голосов
/ 29 октября 2018

Решение с Map и однопетлевым подходом

var array = [{ user: 'Alex', date: '1540801929945' }, { user: 'Bill', date: '1640801929946' }, { user: 'Carl', date: '1740801929947' }, { user: 'Alex', date: '1840801929948' }],
    filtered = Array.from(array
        .reduce((m, o) => !m.has(o.user) || m.get(o.user).data > o.date
            ? m.set(o.user, o)
            : m, new Map)
       .values());
      
console.log(filtered);
.as-console-wrapper { max-height: 100% !important; top: 0; }

Для отсортированных данных (заранее выполните сортировку по date), вы можете использовать Set для фильтрации.

var array = [{ user: 'Alex', date: '1540801929945' }, { user: 'Bill', date: '1640801929946' }, { user: 'Carl', date: '1740801929947' }, { user: 'Alex', date: '1840801929948' }],
    filtered = array
        .sort(({ date: a }, { date: b }) => a - b)
        .filter((s => ({ user }) => !s.has(user) && s.add(user))(new Set));
      
console.log(filtered);
.as-console-wrapper { max-height: 100% !important; top: 0; }
0 голосов
/ 29 октября 2018

Для решения O(N), reduce в объект, индексированный как user, чьи значения равны date s - на каждой итерации, если что-то в этом user уже существует, оставьте только самое низкое date. Затем выполните итерацию объекта entries, чтобы превратить его в массив:

const arr = [
    {user: 'Alex', date: '1540801929945'},
    {user: 'Bill', date: '1640801929946'},
    {user: 'Carl', date: '1740801929947'},
    {user: 'Alex', date: '1840801929948'},
    {user: 'Carl', date: '1340801929947'},
];

const arrByUser = arr.reduce((a, { user, date }) => {
  if (!a[user]) a[user] = date;
  else if (a[user].localeCompare(date) === 1) a[user] = date;
  return a;
}, {});
const output = Object.entries(arrByUser)
  .map(([user, date]) => ({ user, date }));
console.log(output);
0 голосов
/ 29 октября 2018

Уменьшите массив до объекта с ключом user. Если пользователь не находится в unique объекте, или если его дата «старше», чем это, добавьте его к объекту. Преобразовать объект в массив с помощью Object.values().

Примечание: , поскольку у вас даты строковые, преобразуйте их в число при сравнении (я использую оператор + ).

const array = [{ user: 'Alex', date: '1540801929945' }, { user: 'Bill', date: '1640801929946' }, { user: 'Carl', date: '1740801929947' }, { user: 'Alex', date: '1840801929948' }];


const filteredArray = Object.values(array.reduce((unique, o) => {
  if(!unique[o.user] || +o.date > +unique[o.user].date) unique[o.user] = o;
  
  return unique;
}, {}));

console.log(filteredArray);
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...