Объединить массив объектов по свойству с помощью Lodash
У меня есть два массива объектов, которые представляют адреса электронной почты с меткой и значением:
var original = [
{
label: 'private',
value: '[email protected]'
},
{
label: 'work',
value: '[email protected]'
}
];
var update = [
{
label: 'private',
value: '[email protected]'
},
{
label: 'school',
value: '[email protected]'
}
];
Теперь я хочу сравнить и объединить два массива с помощью поля label
, чтобы результат выглядел так:
var result = [
{
label: 'private',
value: '[email protected]'
},
{
label: 'work',
value: '[email protected]'
},
{
label: 'school',
value: '[email protected]'
}
]
Как я могу это сделать, например, используя lodash?
Ответы
Ответ 1
_.unionBy()
:
Этот метод похож на _.union, за исключением того, что он принимает итерацию, которая вызывается для каждого элемента каждого массива для генерации критерия, по которому вычисляется уникальность. Значения результатов выбираются из первого массива, в котором происходит значение.
var original = [
{ label: 'private', value: '[email protected]' },
{ label: 'work', value: '[email protected]' }
];
var update = [
{ label: 'private', value: '[email protected]' },
{ label: 'school', value: '[email protected]' }
];
var result = _.unionBy(update, original, "label");
console.log(result);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.15.0/lodash.min.js"></script>
Ответ 2
Преобразуйте списки в объекты с ключом label
, объедините их с помощью _.assign
и преобразуйте их обратно в массив. Он даже сохранит порядок элементов в большинстве браузеров.
var original = [
{
label: 'private',
value: '[email protected]'
},
{
label: 'work',
value: '[email protected]'
}
];
var update = [
{
label: 'private',
value: '[email protected]'
},
{
label: 'school',
value: '[email protected]'
}
];
console.log(
_.map(
_.assign(
_.mapKeys(original, v => v.label),
_.mapKeys(update, v => v.label)
)
)
);
// or remove more duplicated code using spread
console.log(
_.map(
_.assign(
...[original, update].map(
coll => _.mapKeys(coll, v => v.label)
)
)
)
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.15.0/lodash.js"></script>
Ответ 3
Возможно, немного поздно, но все решения, которые я видел, не присоединяют оба массива правильно, они используют один из массивов для циклического включения, и любые лишние элементы во втором массиве не добавляются (если это так, требуется).
Правильный способ - сортировать оба массива и перемещаться вперед в обоих массивах, объединять элементы совпадений и добавлять отсутствующие элементы из обоих массивов.
Ниже вы найдете полное решение. Это также принимает O (n + m), что является лучшим, что вы можете получить (без затрат на вычисление для самого сортировки). В моем коде я уже получил данные, отсортированные из базы данных.
function mergeObjectsBasedOnKey(array1, array2, compareFn, mergeFn, alreadySorted) {
var array1Index = 0;
var array2Index = 0;
const merged = [];
if (!alreadySorted) {
array1.sort(compareFn);
array2.sort(compareFn);
}
while (array1Index < array1.length && array2Index < array2.length) {
var comparedValue = compareFn(array1[array1Index], array2[array2Index]);
if (comparedValue === 0) {
merged.push(mergeFn(array1[array1Index], array2[array2Index]));
array1Index++;
array2Index++;
} else if (comparedValue < 0) {
merged.push(mergeFn(array1[array1Index]));
array1Index++;
} else {
merged.push(mergeFn(array2[array2Index]));
array2Index++;
}
}
while (array1Index < array1.length) {
merged.push(mergeFn(array1[array1Index]));
array1Index++;
}
while (array2Index < array2.length) {
merged.push(mergeFn(array2[array2Index]));
array2Index++;
}
return merged;
}
const array1 = [{
"id": 10,
isArray1: true
},
{
"id": 11,
isArray1: true
},
{
"id": 12,
isArray1: true
},
];
const array2 = [{
"id": 8,
isArray2: true
},
{
"id": 11,
isArray2: true
},
{
"id": 15,
isArray2: true
},
];
const result = mergeObjectsBasedOnKey(array1, array2, function(a, b) {
return a.id - b.id;
}, function(a, b) {
if (b) {
return _.merge(a, b);
}
return _.merge(a, {
isArray1: true,
isArray2: true
});
});
console.log(result);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.4/lodash.min.js"></script>
Ответ 4
Здесь я создал еще один jsfiddle [https://jsfiddle.net/a0b8f6wg/][1]
, чтобы объединить два массива объектов, используя Lodash.
Ответ 5
Если вы используете lodash 3.x, где _. unionBy() не существует, вы можете объединить _.union()
и _.uniq()
, чтобы получить тот же результат.
var original = [
{ label: 'private', value: '[email protected]' },
{ label: 'work', value: '[email protected]' }
];
var update = [
{ label: 'private', value: '[email protected]' },
{ label: 'school', value: '[email protected]' }
];
var result = _.uniq(_.union(update, original), "label");
console.log(result);