#javascript #arrays #lodash
#javascript #массивы #Lodash
Вопрос:
У меня есть массив, который выглядит следующим образом:
const myArray = [
[
{id: 1, name: 'Liam'},
{id: 2, name: 'Oliver'},
{id: 3, name: 'Jake'},
],
[
{id: 1, name: 'Liam'},
{id: 2, name: 'Oliver'},
{id: 4, name: 'Joe'},
],
]
Мне нужно найти общие элементы по идентификатору и вернуть их в массив, который будет выглядеть примерно так:
[
{id: 1, name: 'Liam'},
{id: 2, name: 'Oliver'},
]
Если нет никакого способа сделать это с помощью Lodash, просто JS тоже может работать.
Обратите внимание, что я не знаю, сколько из этих массивов у меня будет внутри, поэтому он должен работать для любого числа.
Ответ №1:
Вы можете использовать Lodash _.intersectionBy()
. Вам нужно будет распространить myArray
, потому _intersectionBy()
что ожидайте массивы в качестве аргументов, а не один массив массива:
const myArray = [[{"id":1,"name":"Liam"},{"id":2,"name":"Oliver"},{"id":3,"name":"Jake"}],[{"id":1,"name":"Liam"},{"id":2,"name":"Oliver"},{"id":4,"name":"Joe"}]]
const result = _.intersectionBy(...myArray, 'id')
console.log(result)
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.20/lodash.min.js" integrity="sha512-90vH1Z83AJY9DmlWa8WkjkV79yfS2n2Oxhsi2dZbIv0nC4E6m5AbH8Nh156kkM7JePmqD6tcZsfad1ueoaovww==" crossorigin="anonymous"></script>
Комментарии:
1. Я уже пробовал это, но не распространял ‘myArray’, поэтому это дало мне неверные результаты. -.- Решаемая, спасибо!
2. Пожалуйста. Добавлена информация о распространении.
Ответ №2:
Ванильное решение может быть таким же простым, как filter()
вызов первого элемента массива, проверяющий every()
, содержит ли последующий элемент some()
элементы, которые совпадают.
const [srcElement, ...compArray] = [...myArray];
const intersection = srcElement.filter(o => (
compArray.every(arr => arr.some(p => p.id === o.id)))
);
console.log(intersection)
.as-console-wrapper { max-height: 100% !important; top: 0; }
<script>
const myArray = [
[{ id: 1, name: 'Liam' }, { id: 2, name: 'Oliver' }, { id: 3, name: 'Jake' }],
[{ id: 1, name: 'Liam' }, { id: 2, name: 'Oliver' }, { id: 4, name: 'Joe' }],
[{ id: 1, name: 'Liam' }, { id: 2, name: 'Oliver' }, { id: 5, name: 'Dean' }, { id: 6, name: 'Mara' }]
]
</script>
Ответ №3:
Используйте вложенные forEach
циклы и Set
. Просмотрите каждый подмассив и найдите общие элементы на данный момент.
const intersection = ([firstArr, ...restArr]) => {
let common = new Set(firstArr.map(({ id }) => id));
restArr.forEach((arr) => {
const newCommon = new Set();
arr.forEach(({ id }) => common.has(id) amp;amp; newCommon.add(id));
common = newCommon;
});
return firstArr.filter(({ id }) => common.has(id));
};
const myArray = [
[
{ id: 1, name: "Liam" },
{ id: 2, name: "Oliver" },
{ id: 3, name: "Jake" },
],
[
{ id: 1, name: "Liam" },
{ id: 2, name: "Oliver" },
{ id: 4, name: "Joe" },
],
[
{ id: 2, name: "Oliver" },
{ id: 4, name: "Joe" },
],
];
console.log(intersection(myArray));
Ответ №4:
В настоящее время vanilla ES довольно мощен для функциональной работы с коллекциями даже без помощи библиотек утилит. Вы можете использовать обычные Array
методы, чтобы получить чисто JS-решение. Я создал два примера с использованием чистого JS. Конечно, может быть и больше подходов. И если вы уже используете Lodash в своем приложении, вероятно, было бы лучше просто использовать его высокоуровневую реализацию в форме _.intersectionBy()
, предложенной выше, чтобы уменьшить сложность кода.
const myArray = [
[
{id: 1, name: 'Liam'},
{id: 2, name: 'Oliver'},
{id: 3, name: 'Jake'},
],
[
{id: 1, name: 'Liam'},
{id: 2, name: 'Oliver'},
{id: 4, name: 'Joe'},
],
];
// Regular functional filter-reduce
const reducer = (accum, x) => {
return accum.findIndex(y => x.id == y.id) < 0
? [...accum, x]
: accum;
};
const resultFilterReduce = myArray
.flat()
.filter(x => myArray.every(y => y.findIndex(obj => obj.id === x.id) > -1))
.reduce(reducer, []);
console.log(resultFilterReduce);
// Filter-reduce with using of "HashMap" to remove duplicates
const resultWithHashMap = Object.values(
myArray
.flat()
.filter(x => myArray.every(y => y.findIndex(obj => obj.id === x.id) > -1))
.reduce((accum, x) => {
accum[x.id] = x;
return accum;
}, {})
);
console.log(resultWithHashMap);
Комментарии:
1. Они фактически возвращают плоский массив уникальных (по идентификатору) объектов, как и ожидалось в примере в вопросе.
2. Ожидаемый результат операции — это пересечение [{id: 1, имя: ‘Liam’}, {id: 2, имя: ‘Oliver’}] (элементы, которые появляются хотя бы один раз в каждом массиве). Вы возвращаете объединение [{id: 1, имя: ‘Liam’ }, {id: 2, имя: ‘Oliver’ }, {id: 3, имя: ‘Jake’ }, {id: 4, имя: ‘Joe’ }] (все элементы, которые появляются ввсе массивы).
3. @pilchard Вчера я был невнимателен, когда создал тупой ответ «найти уникальный». Спасибо, что осветили для меня проблему с реальной темой. Я отредактировал свой ответ, чтобы решить проблему в вопросе с помощью тех подходов с уменьшением фильтра и «хэш-карты», о которых я думал раньше, но правильно. 🙂