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

1

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

Пример. Для массива объектов, который может выглядеть так, цель будет состоять в том, чтобы отфильтровать все "пользовательские" дубликаты и сохранить один со старым свойством "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;
},[]);

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

  • 0
    ваши данные отсортированы по date ?
  • 0
    Нет, к сожалению нет. Объекты в реальном случае гораздо больше и сортируются по-разному в зависимости от того, где они используются ...
Показать ещё 2 комментария
Теги:
arrays
filter
duplicates
javascript-objects

4 ответа

1
Лучший ответ

Уменьшите массив до объекта с помощью 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);
  • 0
    Я предполагаю, что это (...) +o.date < +unique[o.user].date) (...) - но в остальном это похоже на работу. Большое спасибо за помощь!
  • 0
    @ YvonC - я не уверен, к чему относится ваш комментарий. Ваши объекты включают в себя date , а не dateofpost .
Показать ещё 1 комментарий
1

Решение с 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

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

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

Дайте ему попробовать, это не больно :)

0

Для решения O(N) reduce объект, проиндексированный user, значения которого - date - на каждой итерации, если что-то у этого 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);

Ещё вопросы

Сообщество Overcoder
Наверх
Меню