Объедините два массива, избегая дубликатов, используя неизменный шаблон в Redux - PullRequest
0 голосов
/ 12 декабря 2018

Допустим, у меня есть два массива:

let A = [a,b,c,d]
let B = [c,d,e]

, где каждая буква является объектом, обладающим несколькими свойствами, одним из которых является id, который уникален в моем домене.Тогда объединенный результат будет иметь вид

[a,b,c,d,e]

, где [c,d] происходит от B.

Используя элегантный подход, как бы я объединил эти два массива так, как любой элемент в B перезапишет любой существующий в A, а все остальные останутся нетронутыми.Так что это союз с B элементами, имеющими приоритет в случае конфликта.

У меня есть две идеи (с использованием ES6 и lodash):

//remove same elements first, then join arrays
let ids = new Set(B.map(e => e.id));
let newState = _.reject(A, constraint => ids.has(constraint.id));
return newState.concat(B);

//convert both to hashmap, join, then take values
let B_map = _.keyBy(B, 'id');
let A_map = _.keyBy(A, 'id');
return {...A_map, ...B_map}.values();

Есть более короткий / более краткий/ более читаемая версия?Может быть, один без внешних зависимостей?По сути, я ищу что-то вроде

Где равенство между любым элементом определяется свойством id (или функцией сравнения в v2).

Ответы [ 3 ]

0 голосов
/ 12 декабря 2018

Поскольку вы уже используете lodash, вы можете использовать _.unionBy, который объединяет массивы, используя критерий, по которому вычисляется уникальность:

let result = _.unionBy(B, A, "id");

Начните с B до A, чтобыв случае дубликатов вместо значений A принимаются значения B.

Пример:

let A = [
  { id: "a", arr: "A" },
  { id: "b", arr: "A" },
  { id: "c", arr: "A" },
  { id: "d", arr: "A" }
];

let B = [
  { id: "b", arr: "B" },
  { id: "d", arr: "B" }
];

let result = _.unionBy(B, A, "id");

console.log(result);
<script src="https://cdn.jsdelivr.net/npm/lodash@4.17.11/lodash.min.js"></script>

Примечание: Это приводит к неправильному порядку элементов, сначала идут дубликаты, а затем остальные.

0 голосов
/ 12 декабря 2018

Используйте lodash's _.differenceBy(A, B), чтобы удалить все элементы, которые есть в B, из A, а затем объединить с B элементами.Это сохранит порядок элементов A перед элементами B.

const A = [{"id":"a","arr":"A"},{"id":"b","arr":"A"},{"id":"c","arr":"A"},{"id":"d","arr":"A"}];

const B = [{"id":"c","arr":"B"},{"id":"d","arr":"B"}];

const result = [..._.differenceBy(A, B, 'id'), ...B];

console.log(result);
<script src="https://cdn.jsdelivr.net/npm/lodash@4.17.11/lodash.min.js"></script>
0 голосов
/ 12 декабря 2018

Без внешних зависимостей вы можете использовать filter для извлечения элементов из A, у которых нет идентификаторов в B и concat, с B:

const A = [{id: 1, name: 'x'}, {id: 2, name: 'y'}, {id: 3, name: 'z'}];
const B = [{id: 2, name: 'hello'}];

let ids = new Set(B.map(e => e.id));
let newState = A.filter(a => !ids.has(a.id)).concat(B);

console.log(newState);
...