Empresas
Empregos
  • Sobre nós
  • Soluções
    • Publicação de vagas
      Publique sua vaga e receba candidatos qualificados em 48h.
    • Avaliações de candidatos
      Mais de 500 testes técnicos e psicológicos, mais anti-fraude.
    • Headhunting
      Busca executiva personalizada do início ao fim.
    • Folha de Pagamento + EOR
      Dispersão de folha e EOR em mais de 15 países da LATAM.
  • Preços
  • Empregos

0

138
Visualizações
Merge 2 arrays of objects but concat arrays if properties has the same value

I have two objects with the next structure:

let sourceObj = [
                    {
                        items: [
                            { items: [{ id: '0', name: 'z' }], name: 'm' },
                            { items: [{ id: '2', name: 'q' }], name: 'l' },
                        ],
                        name: 'c'
                    },
                    {
                        items: [
                            { items: [{ id: '4', name: '-' }], name: 'v' },
                        ],
                        name: 'd'
                    }
                ];

let targetObj = [
                    {
                        items: [
                            { items: [{ id: '1', name: 'd' }], name: 'm' },
                            { items: [{ id: '3', name: 'b' }], name: 'j' },
                        ],
                        name: 'c'
                    }
                ];

I want to merge this object to get one object with the next structure:

let merged =    [
                    {
                        items: [
                            { items: [
                                { id: '0', name: 'd' }, 
                                { id: '1', name: 'z' }], 
                              name: 'm' 
                            },
                            { items: [{ id: '2', name: 'q' }], name: 'l' },
                            { items: [{ id: '3', name: 'b' }], name: 'j' },
                        ],
                        name: 'c'
                    },
                    {
                        items: [
                            { items: [{ id: '4', name: '-' }], name: 'v' },
                        ],
                        name: 'd'
                    }
                ]

That is I want to get the object, which has joined arrays if the name of the source array is the same in the target array.

I tried use lodash method mergeWith, but I could join only upper items level of collections...

mergeWith(sourceObj, targetObj, (objValue, srcValue) => {
          if (isArray(objValue)) {
            return objValue.concat(srcValue);
          }
        });
about 4 years ago · Juan Pablo Isaza
2 Respostas
Responde à pergunta

0

You are correct in that Lodash's mergeWith doesn't merge recursively. You can manage this yourself manually.

  1. First iterate the first array and generate a map object by the name property.
  2. Then iterate the second array and check if the name property matches, and if so, recursively call the merge function to merge the two nested arrays from source and target arrays, otherwise, add the second array's element to the object map.
  3. Finally, convert the map object back to an array of the merged values.

Code:

const merge = (sourceArr, targetArr) => {
  // (1) generate lookup map
  const objMap = sourceArr.reduce((map, curr) => {
    return {
      ...map,
      [curr.name]: curr
    };
  }, {});

  // (2) Merge objects, recurse on items arrays
  targetArr.forEach((obj) => {
    if (objMap[obj.name]) {
      objMap[obj.name].items = merge(objMap[obj.name].items, obj.items);
    } else {
      objMap[obj.name] = obj;
    }
  });

  // (3) Return merged values array
  return Object.values(objMap);
};

const sourceObj = [
  {
    items: [
      { items: [{ id: "0", name: "z" }], name: "m" },
      { items: [{ id: "2", name: "q" }], name: "l" }
    ],
    name: "c"
  },
  {
    items: [{ items: [{ id: "4", name: "-" }], name: "v" }],
    name: "d"
  }
];

const targetObj = [
  {
    items: [
      { items: [{ id: "1", name: "d" }], name: "m" },
      { items: [{ id: "3", name: "b" }], name: "j" }
    ],
    name: "c"
  }
];

const merge = (sourceArr, targetArr) => {
  const objMap = sourceArr.reduce((map, curr) => {
    return {
      ...map,
      [curr.name]: curr
    };
  }, {});

  targetArr.forEach((obj) => {
    if (objMap[obj.name]) {
      objMap[obj.name].items = merge(objMap[obj.name].items, obj.items);
    } else {
      objMap[obj.name] = obj;
    }
  });

  return Object.values(objMap);
};

const res = merge(sourceObj, targetObj);

console.log(res);

about 4 years ago · Juan Pablo Isaza Relatório

0

I find a dose of mutual recursion makes for cleaner code here.

const combineItems = (o = {}, items) =>
  o .items || items .length ? {items: deepMerge (o.items || [], items)} : {} 

const deepMerge = (xs, ys) => 
  Object .values ([... xs, ... ys] .reduce (
    (a, {name, items = [], ...rest}) => ({
      ... a,
      [name]: {
        ... (a [name] || {name, ...rest}),
        ... combineItems (a [name], items)
      }
    }), {}
  ))

const sourceObj = [{items: [{items: [{id: "0", name: "z"}], name: "m"}, {items: [{id: "2", name: "q"}], name: "l"}], name: "c"}, {items: [{items: [{id: "4", name: "-"}], name: "v"}], name: "d"}]
const targetObj = [{items: [{items: [{id: "1", name: "d"}], name: "m"}, {items: [{id: "3", name: "b"}], name: "j"}], name: "c"}];

console .log (deepMerge (sourceObj, targetObj))
.as-console-wrapper {max-height: 100% !important; top: 0}

deepMerge is the main function, but it delegates to combineItems to handle the various combinations of whether we already have items to combine or not. combineItems will return something like {items: [<item1>. <item2>, ...]} or just {}, depending upon whether any items have been found.

There is a potential performance problem here, which Rich Snapp has dubbed the The reduce ({...spread}) anti-pattern. I personally would not worry about it here if the code is performing to your satisfaction. But if not, we can change it to match his suggestions, to something like this:

const deepMerge = (xs, ys) => 
  Object .values ([... xs, ... ys] .reduce (
    (a, {name, items = [], ...rest}) => {
      const x = a [name] || {name, ...rest}
      if (items.length || x.items)
      x .items = deepMerge (x .items || [], items)
      a [name] = x
      return a
    }, {}
  ))
about 4 years ago · Juan Pablo Isaza Relatório
Responde à pergunta
Encontrar trabalhos remotos

Descubra a nova forma de encontrar um emprego!

melhores empregos
Principais categorias de trabalho
Empresas
Postar vaga Preços Comercial
Jurídico
Termos e Condições Política de privacidade
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Recomende algumas ofertas para mim
Preciso de ajuda