bossajie
bossajie

Reputation: 328

Merge nested array with unique element in Javascript

How can I achieve this without using any library? I have tried it with some ES6 function but it ended up duplicating some items in the array. It should return unique especially when there is no child array in the array

I have three array variables:

data1 = first data

data2 = variable to be merge with data1

data3 = result of the merged variables

        let data1 = [{
            "document_id": 12264,
            "detail_info": [{
                "id": 745,
                "lot_no": "X12345",
              },
              {
                "id": 744,
                "lot_no": "Z12345",
              }
            ]
          },
          {
            "document_id": 12226,
            "detail_info": [{
                "id": 738,
                "lot_no": "B12345",
              },
              {
                "id": 739,
                "lot_no": "C12345",
              }
            ]
          },
          {
            "document_id": 12221,
            "detail_info": []
          }
        ]

        let data2 = [{
            "document_id": 12264,
            "detail_info": [{
                "id": 744,
                "lot_no": "Z12345",
              },
              {
                "id": 743,
                "lot_no": "L12345",
              }
            ]
          },
          {
            "document_id": 12226,
            "detail_info": [{
              "id": 739,
              "lot_no": "C12345",
            }]
          },
          {
            "document_id": 12229,
            "detail_info": [{
              "id": 741,
              "lot_no": "E12345",
            }]
          },
          {
            "document_id": 10095,
            "detail_info": []
          }
        ]

//**This should be the result**
      let data3=[
      {
        "document_id": 12264,
        "detail_info": [
          {
            "id": 745,
            "lot_no": "X12345",
          },
          {
            "id": 744,
            "lot_no": "Z12345",
          },
          {
            "id": 743,
            "lot_no": "L12345",
          }
        ]
      },
      {
        "document_id": 12226,
        "detail_info": [
          {
            "id": 738,
            "lot_no": "B12345",
          },
          {
            "id": 739,
            "lot_no": "C12345",
          }
        ]
      },
      {
        "document_id": 12221,
        "detail_info": []
      },
      {
        "document_id": 12229,
        "detail_info": [
          {
            "id": 741,
            "lot_no": "E12345",
          }
        ]
      },
      {
        "document_id": 10095,
        "detail_info": []
      }
    ]

Upvotes: 3

Views: 319

Answers (2)

jo_va
jo_va

Reputation: 13993

First concatenate data1 and data2 into a single array ([...data1, ...data2]).

Then with Array.reduce(), generate a dictionary whose keys are all possible document_id found in the array.

Inside reduce, when an entry already exists for a document_id, then you have to merge the detail_info together. Create an array of all detail_info from the existing entry and the current item and remove the duplicates using a Set that you generate from the detail_info.id, then map this Set of ids to the the corresponding detail_info entries.

Finally, convert the dictionary to an array with Object.values():

const data1 = [
  { "document_id": 12264, someData: 'hello', "detail_info": [{ "id": 745, "lot_no": "X12345" },  { "id": 744, "lot_no": "Z12345" }] },
  { "document_id": 12226, "detail_info": [{ "id": 738, "lot_no": "B12345" }, { "id": 739, "lot_no": "C12345" }] },
  { "document_id": 12221, "detail_info": [] }
];

const data2 = [
  { "document_id": 12264, "detail_info": [{ "id": 744, "lot_no": "Z12345" }, { "id": 743, "lot_no": "L12345" }] },
  { "document_id": 12226, "detail_info": [{ "id": 739, "lot_no": "C12345" }] },
  { "document_id": 12229, "detail_info": [{ "id": 741, "lot_no": "E12345" }] },
  { "document_id": 10095, "detail_info": [] }
];

const distinctById = arr => [...new Set(arr.map(({ id }) => id))]
  .map(id => arr.find(info => info.id === id))

const data3 = Object.values([...data1, ...data2].reduce((acc, x) => {
  acc[x.document_id] = acc[x.document_id] || { ...x, detail_info: [] };
  acc[x.document_id].detail_info = distinctById([...acc[x.document_id].detail_info, ...x.detail_info]);
  return acc;
}, {}));

console.log(data3);

If you want to keep your detail_info array ordered by insertion, do this:

const distinctById = arr => {
  const uniqueIds = new Set(arr.map(({ id }) => id));
  return arr.filter(({ id }) => uniqueIds.delete(id));
}

console.log(distinctById([{ id: 5 }, { id: 4 }, { id: 5 }, { id: 3 }, { id: 4 }]))

Upvotes: 2

Jack Bashford
Jack Bashford

Reputation: 44135

If you just want to combine two arrays, use concat:

let data3 = data1.concat(data2);

Upvotes: 0

Related Questions