Простой подход состоит в том, чтобы просто написать функцию отображения, которая копирует новые объекты на основе соответствующих ключей.
При заданном интерфейсе:
interface MyInterface {
key: string;
value: number;
}
И двух массивах:
const existingArray: MyInterface[] = [
{ key: 'a', value: 1 },
{ key: 'b', value: 2 },
{ key: 'c', value: 3 }
];
const newArray: MyInterface[] = [
{ key: 'b', value: 20 },
{ key: 'c', value: 30 },
{ key: 'd', value: 40 }
];
Ожидаемый результат
Я хочу обновить existingArray
значениями newArray
, где ключи совпадают.
- Если значение не найдено в
newArray
, существующий элемент остается неизменным. - Если в
newArray
найдено новое значение, оно не объединяется в в oldArray
- Все значения свойств должны быть перезаписаны
Мой ожидаемый результат:
const expected = [
{ key: 'a', value: 1 },
{ key: 'b', value: 20 },
{ key: 'c', value: 30 }
];
Solution
Я бы достиг этого с помощью этой функции слияния. Это просто карта массива javascript:
private merge<T>(existing: T[], updated: T[], getKey: (t: T) => string): T[] {
// start with the existing array items
return existing.map(item => {
// get the key using the callback
const key: string = getKey(item);
// find the matching item by key in the updated array
const matching: T = updated.find(x => getKey(x) === key);
if (matching) {
// if a matching item exists, copy the property values to the existing item
Object.assign(item, matching);
}
return item;
});
}
Я сделал ее обобщенной c, чтобы вы могли использовать ее с любым типом. Все, что вам нужно сделать, это предоставить 2 массива и обратный вызов для определения ключа.
Я бы использовал его для создания объединенного массива следующим образом:
const merged = this.merge(existingArray, newArray, x => x.key);
DEMO: https://stackblitz.com/edit/angular-nn8hit
Слово предупреждения
Это не будет хорошо масштабироваться с очень большими массивами. Если вы используете большие массивы, я бы оптимизировал, создав индексы типа Map<string, T>
, чтобы фиксировать число циклов. Эта реализация выходит за рамки этого вопроса.
Редактировать:
Если вы хотите обновить только определенные значения c, вы можете передать обратный вызов обновления:
private merge<T>(existing: T[], updated: T[], getKey: (t: T) => string,
update: (item, matching) => void
): T[] {
return existing.map(item => {
const key: string = getKey(item);
const matching: T = updated.find(x => getKey(x) === key);
if (matching) {
update(item, matching);
}
return item;
});
}
И назовите это так:
const merged = this.merge(existingArray, newArray, x => x.key,
(item, matching) => item.value = matching.value);