Объединить массив объектов и получить уникальные значения

У меня есть два массива, содержащие вложенные объекты. Я хотел бы объединить их и получить уникальный массив

У меня есть эти два массива

// ARRAY 1
let variants = [
  {color: "Red", sizes: "Small", material: "Cotton", price: "$100", ...},
  {color: "Red", sizes: "Large", material: "Cotton", price: "$120", ...},
  {color: "Blue", sizes: "Small", material: "Cotton", price: "$150", ...},
  {color: "Blue", sizes: "Large", material: "Cotton", price: "$180", ...},
]
// ARRAY 2
let newVariants = [
  {color: "Red", sizes: "Small", material: "Cotton"}, // this one is already exist in ARRAY 1
  {color: "Red", sizes: "Large", material: "Cotton"}, // this one is already exist in ARRAY 1
  {color: "Blue", sizes: "Small", material: "Cotton"}, // this one is already exist in ARRAY 1
  {color: "Blue", sizes: "Large", material: "Wool"}, // this one is new object
  {color: "Green", sizes: "Large", material: "Cotton"}, // this one is new object
]

и я хочу этого

[
  {color: "Red", sizes: "Small", material: "Cotton", price: "$100"},
  {color: "Red", sizes: "Large", material: "Cotton", price: "$120"},
  {color: "Blue", sizes: "Small", material: "Cotton", price: "$150"},
  {color: "Blue", sizes: "Large", material: "Cotton", price: "$180"},
  {color: "Blue", sizes: "Large", material: "Wool", price: null, ...},
  {color: "Green", sizes: "Large", material: "Cotton", price: null, ...}
]

Примечание. Значение МАССИВА 1 всегда заменяет значение МАССИВА 2.

Спасибо!


person Muhammad Taseen    schedule 08.03.2021    source источник
comment
Имеет ли значение порядок объектов в выходном массиве?   -  person Nick Parsons    schedule 08.03.2021


Ответы (4)


Я бы объединил два массива с массивом2, предшествующим массиву1. Затем вы можете использовать .reduce() для создания объекта (т. е. Map) с ключом, состоящим из конкатенированной строки значений, которые вы хотите объединить. Имея второй массив array1 в ваших объединенных массивах, ключ/значения из объектов внутри этого будут перезаписывать те из массива2 (и поэтому объекты массива1 будут иметь приоритет):

let variants = [ {color: "Red", sizes: "Small", material: "Cotton", price: "$100",}, {color: "Red", sizes: "Large", material: "Cotton", price: "$120",}, {color: "Blue", sizes: "Small", material: "Cotton", price: "$150",}, {color: "Blue", sizes: "Large", material: "Cotton", price: "$180",}, ];
let newVariants = [ {color: "Red", sizes: "Small", material: "Cotton"}, {color: "Red", sizes: "Large", material: "Cotton"}, {color: "Blue", sizes: "Small", material: "Cotton"}, {color: "Blue", sizes: "Large", material: "Wool"}, {color: "Green", sizes: "Large", material: "Cotton"}, ];

const res = Array.from([...newVariants, ...variants].reduce((acc, {price=null, ...rest}) => {
  const key = Object.entries(rest).join("-"); // get a key based on the values (excluding the price)
  return acc.set(key, {...rest, price});
}, new Map).values());

console.log(res);

В противном случае, если порядок выходного массива имеет значение, вы можете изменить порядок слияния массивов и использовать проверку, чтобы увидеть, было ли уже установлено значение, прежде чем добавлять его в качестве значения в ваш объект:

let variants = [ {color: "Red", sizes: "Small", material: "Cotton", price: "$100",}, {color: "Red", sizes: "Large", material: "Cotton", price: "$120",}, {color: "Blue", sizes: "Small", material: "Cotton", price: "$150",}, {color: "Blue", sizes: "Large", material: "Cotton", price: "$180",}, ];
let newVariants = [ {color: "Red", sizes: "Small", material: "Cotton"}, {color: "Red", sizes: "Large", material: "Cotton"}, {color: "Blue", sizes: "Small", material: "Cotton"}, {color: "Blue", sizes: "Large", material: "Wool"}, {color: "Green", sizes: "Large", material: "Cotton"}, ];

const res = Array.from([...variants, ...newVariants].reduce((acc, {price=null, ...rest}) => {
  const key = Object.entries(rest).join("-"); // get a key based on the values (excluding the price)
  return acc.set(key, acc.get(key) || {...rest, price});
}, new Map).values());

console.log(res);

person Nick Parsons    schedule 08.03.2021

Значение МАССИВА 1 всегда будет замещать значение МАССИВА 2.

Вы можете фильтровать, используя .filter и .some, как показано ниже:

let variants = [ {color: "Red", sizes: "Small", material: "Cotton", price: "$100",}, {color: "Red", sizes: "Large", material: "Cotton", price: "$120",}, {color: "Blue", sizes: "Small", material: "Cotton", price: "$150",}, {color: "Blue", sizes: "Large", material: "Cotton", price: "$180",}, ];
let newVariants = [ {color: "Red", sizes: "Small", material: "Cotton"}, {color: "Red", sizes: "Large", material: "Cotton"}, {color: "Blue", sizes: "Small", material: "Cotton"}, {color: "Blue", sizes: "Large", material: "Wool"}, {color: "Green", sizes: "Large", material: "Cotton"}, ];

const isEqual = (p1, p2) => p1.color == p2.color && p1.sizes == p2.sizes && p1.material == p2.material;
const filteredExtraVariants = newVariants.filter(p1 => !variants.some(p2 => isEqual(p1, p2)));
const extraVariants = filteredExtraVariants.map(r => 
{
  r.price = null;
  return r;
});

const result = variants.concat(extraVariants);
console.log(result);

person Nguyễn Văn Phong    schedule 08.03.2021
comment
Эй, Фонг, спасибо за вашу помощь, я очень ценю ее, я принимаю ответ Ника, потому что я не хочу использовать реквизиты второго объекта в функции фильтра, эти реквизиты могут каждый раз меняться, но я голосую за оба ответа от вас. Спасибо еще раз - person Muhammad Taseen; 09.03.2021

Ты можешь сделать:

const variants = [{ color: "Red", sizes: "Small", material: "Cotton", price: "$100" }, { color: "Red", sizes: "Large", material: "Cotton", price: "$120" }, { color: "Blue", sizes: "Small", material: "Cotton", price: "$150" }, { color: "Blue", sizes: "Large", material: "Cotton", price: "$180" }]
const newVariants = [{ color: "Red", sizes: "Small", material: "Cotton" }, { color: "Red", sizes: "Large", material: "Cotton" }, { color: "Blue", sizes: "Small", material: "Cotton" }, { color: "Blue", sizes: "Large", material: "Wool" }, { color: "Green", sizes: "Large", material: "Cotton" }]

const result = Object.values(
  [...newVariants, ...variants].reduce((a, { color, sizes, material, price = null }) =>
    (a[`${color}-${sizes}-${material}`] = { color, sizes, material, price }, a), {})
)

console.log(result)

person Yosvel Quintero Arguelles    schedule 08.03.2021

Другой способ — использовать .reduce, как показано ниже:

const variants = [{ color: "Red", sizes: "Small", material: "Cotton", price: "$100" }, { color: "Red", sizes: "Large", material: "Cotton", price: "$120" }, { color: "Blue", sizes: "Small", material: "Cotton", price: "$150" }, { color: "Blue", sizes: "Large", material: "Cotton", price: "$180" }]
const newVariants = [{ color: "Red", sizes: "Small", material: "Cotton" }, { color: "Red", sizes: "Large", material: "Cotton" }, { color: "Blue", sizes: "Small", material: "Cotton" }, { color: "Blue", sizes: "Large", material: "Wool" }, { color: "Green", sizes: "Large", material: "Cotton" }]

const result = [...variants, ...newVariants].reduce((acc, {color, sizes, material, price = null}) => {
   const key = `${color}-${sizes}-${material}`;
   acc[key] ??= {color, sizes, material, price};
   return acc;
  }, {});

console.log(Object.values(result))

person Nguyễn Văn Phong    schedule 08.03.2021