У меня есть коллекция со свойствами идентификатора и номера версии. Я хочу отфильтровать эти данные, чтобы отображалась только последняя запись каждого из них.
const data = [
{
id: 1,
version: 1
},
{
id: 1,
version: 2
},
{
id: 1,
version: 3
},
{
id: 2,
version: 1
},
{
id: 3,
version: 1
},
{
id: 3,
version: 2
}
];
После фильтра должно быть:
const data = [
{
id: 1,
version: 1
},
{
id: 2,
version: 1
},
{
id: 3,
version: 2
}
];
Каков наилучший способ сделать этот фильтр с меньшей сложностью/порядком? использование lodash разрешено.
Я думал отсортировать по номеру версии и выбрать все данные с наибольшим номером версии, затем перейти к следующей более низкой версии и проверить, существует ли она в данных, затем оставить ее, если не добавить, и так далее до версии достигает 1. Однако я не уверен, что это лучший способ и как я пишу его с помощью утилит lodash.
Это кажется достаточно эффективным: сортировка по идентификатору и версии за один проход, затем вы можете просто отфильтровать до последнего экземпляра каждого идентификатора, потому что это будет тот, у которого самый высокий номер версии. Конечно, если ваши данные предварительно отсортированы, вы можете сразу перейти к самой интересной части; Я переупорядочил исходные данные здесь, чтобы показать, как работает сортировка:
const latestVersions = d => {
// sort by ID and version:
d = d.sort((a, b) => {
if (a.id === b.id) {
return a.version - b.version
} else {
return a.id - b.id
}
}).filter((a, i) => {
// only return elements that aren't followed by another with the same ID:
return d[i + 1]?.id !== a.id
})
return d
}
const data = [{
id: 1,
version: 2
},
{
id: 2,
version: 1
},
{
id: 3,
version: 2
},
{
id: 1,
version: 1
},
{
id: 1,
version: 3
},
{
id: 3,
version: 1
}
];
console.info(latestVersions(data))
Не по теме: можно .sort((a, b) => a.id - b.id || a.version - b.version)
Истинный! Я думаю, что так читать немного сложнее, но это действительно работает.
С помощью lodash сгруппируйте по id, затем сопоставьте и возьмите объект с максимальным version из каждой группы.
Примечание. _.groupBy преобразует массив в объект, используя id в качестве ключа, и, поскольку вы используете целочисленные идентификаторы, порядок будет меняться в соответствии с числовыми значениями id. Если это проблема, см. второе решение.
const { map, groupBy, maxBy } = _
const data = [{"id":1,"version":1},{"id":1,"version":2},{"id":1,"version":3},{"id":2,"version":1},{"id":3,"version":1},{"id":3,"version":2}]
const result = map(
groupBy(data, 'id'),
g => maxBy(g, 'version')
)
console.info(result)
<script src = "https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.21/lodash.min.js" integrity = "sha512-WFN04846sdKMIP5LKNphMaWzU7YpMyCU245etK3g/2ARYbPK9Ub18eG+ljU96qKRCWh+quCY7yefSmlkQw1ANQ= = " crossorigin = "anonymous" referrerpolicy = "no-referrer"></script>
Vanilla JS, уменьшите массив до карты. Для каждого элемента проверьте, существует ли он на карте, и если его нет или его версия больше, чем версия на карте, установите текущий объект для этого id. Преобразуйте значения карты обратно в массив, используя Array.from().
Примечание. Использование карты сохраняет исходный порядок элементов массива.
const data = [{"id":1,"version":1},{"id":1,"version":2},{"id":1,"version":3},{"id":2,"version":1},{"id":3,"version":1},{"id":3,"version":2}]
const result = Array.from(data.reduce((acc, o) =>
acc.has(o.id) && acc.get(o.id).version >= o.version
? acc
: acc.set(o.id, o)
, new Map()).values())
console.info(result)
Вы можете попробовать следующий подход:
{ id: key, version: value }
const data = [{"id":1,"version":1},{"id":1,"version":2},{"id":1,"version":3},{"id":2,"version":1},{"id":3,"version":1},{"id":3,"version":2}]
const map = data.reduce(
(acc, {id, version}) => ({ ...acc, [id]: version}),
{}
)
const result = Object.entries(map).map(([k, v]) => ({id: k, version: v}))
console.info(result)
Почему версия id 1 — 1, а версия id 3 — 2?