简体   繁体   中英

Map arrays using union or intersection to produce a third array

I am trying to solve a problem in Angular 7, where i need to write a function that takes two array of objects, in this case, the first one and the second one, and returns the third array.

The third array is very similar to the first array, but the value of the count key in the children array is dependent on whether there are any children in the second array or if present, reflect the value of count in that object. Is there an array map function in angular that can solve this?

First array:

[
    {
        "name": "Category 1",
        "value": "Vegetables",
        "children": [
            {"name": "Carrots", "value": "Carrots", "count": 2},
            {"name": "Peas", "value": "Peas", "count": 1}
        ]
    },
    {
        "name": "Category 2",
        "value": "Fruits",
        "children": [
            {"name": "Apples", "value": "Apples", "count": 10},
            {"name": "Bananas", "value": "Bananas", "count": 5}
        ]
    },
    {
        "name": "Category 3",
        "value": "Desserts",
        "children": [
            {"name": "Ice Cream", "value": "IceCream", "count": 3},
            {"name": "Cakes", "value": "Cakes", "count": 3}
        ]
    }
]

Second array

[
    {
        "name": "Category 1",
        "value": "Vegetables",
        "children": [
            {"name": "Peas", "value": "Peas", "count": 1}
        ]
    },
    {
        "name": "Category 2",
        "value": "Fruits",
        "children": [
            {"name": "Apples", "value": "Apples", "count": 3},
            {"name": "Bananas", "value": "Bananas", "count": 2}
        ]
    },
    {
        "name": "Category 3",
        "value": "Desserts",
        "children": []
    }
]

Third array

[
    {
        "name": "Category 1",
        "value": "Vegetables",
        "children": [
            {"name": "Carrots", "value": "Carrots", "count": 0},
            {"name": "Peas", "value": "Peas", "count": 1}
        ]
    },
    {
        "name": "Category 2",
        "value": "Fruits",
        "children": [
            {"name": "Apples", "value": "Apples", "count": 3},
            {"name": "Bananas", "value": "Bananas", "count": 2}
        ]
    },
    {
        "name": "Category 3",
        "value": "Desserts",
        "children": [
            {"name": "Ice Cream", "value": "IceCream", "count": 0},
            {"name": "Cakes", "value": "Cakes", "count": 0}
        ]
    }
]

You can do this quite simply with map and find , then reduce the array afterwards.

 const arr1 = [{"name":"Category 1","value":"Vegetables","children":[{"name":"Carrots","value":"Carrots","count":2},{"name":"Peas","value":"Peas","count":1}]},{"name":"Category 2","value":"Fruits","children":[{"name":"Apples","value":"Apples","count":10},{"name":"Bananas","value":"Bananas","count":5}]},{"name":"Category 3","value":"Desserts","children":[{"name":"Ice Cream","value":"IceCream","count":3},{"name":"Cakes","value":"Cakes","count":3}]}]; const arr2 = [{"name":"Category 1","value":"Vegetables","children":[{"name":"Peas","value":"Peas","count":1}]},{"name":"Category 2","value":"Fruits","children":[{"name":"Apples","value":"Apples","count":3},{"name":"Bananas","value":"Bananas","count":2}]},{"name":"Category 3","value":"Desserts","children":[]}]; const res = arr1.map(({ name, value, children }) => { let found = arr2.find(({ name: n, value: v }) => n == name && v == value); if (found) children = children.concat(found.children).reduce((a, c) => { let f = a.findIndex(({ name: n }) => n == c.name); if (f > -1) a[f].count += c.count; else a.push(c); return a; }, []); return { name, value, children }; }); console.log(res); 
 .as-console-wrapper { max-height: 100% !important; top: auto; } 

Here idea is

  • First change the second array to object so it becomes easier to find values on it
  • Now loop through array1 and take the respective children from array2
  • Loop on children of array1 and change value according to children from array2

 const arr1 = [{"name":"Category 1","value":"Vegetables","children":[{"name":"Carrots","value":"Carrots","count":2},{"name":"Peas","value":"Peas","count":1}]},{"name":"Category 2","value":"Fruits","children":[{"name":"Apples","value":"Apples","count":10},{"name":"Bananas","value":"Bananas","count":5}]},{"name":"Category 3","value":"Desserts","children":[{"name":"Ice Cream","value":"IceCream","count":3},{"name":"Cakes","value":"Cakes","count":3}]}]; const arr2 = [{"name":"Category 1","value":"Vegetables","children":[{"name":"Peas","value":"Peas","count":1}]},{"name":"Category 2","value":"Fruits","children":[{"name":"Apples","value":"Apples","count":3},{"name":"Bananas","value":"Bananas","count":2}]},{"name":"Category 3","value":"Desserts","children":[]}]; let arr2Obj = Object.fromEntries(arr2.map(val => [val.name, val])) const res = arr1.map(({ name, value, children }) => { let arr2Children = ( arr2Obj[name] || {} ).children let childrenObj = Object.fromEntries(arr2Children.map(val => [val.name,val])) let newChildren = children.map( val => { let count = (childrenObj[val.name] || {}).count || 0 return {...val,count} }) return {name,value,children:newChildren} }); console.log(res); 
 .as-console-wrapper { max-height: 100% !important; top: auto; } 

PS:- If your array1 and array2 are always in sorted manner than you need not to change it object and you can directly access using index, same for the children

 const arr1 = [{"name":"Category 1","value":"Vegetables","children":[{"name":"Carrots","value":"Carrots","count":2},{"name":"Peas","value":"Peas","count":1}]},{"name":"Category 2","value":"Fruits","children":[{"name":"Apples","value":"Apples","count":10},{"name":"Bananas","value":"Bananas","count":5}]},{"name":"Category 3","value":"Desserts","children":[{"name":"Ice Cream","value":"IceCream","count":3},{"name":"Cakes","value":"Cakes","count":3}]}]; const arr2 = [{"name":"Category 1","value":"Vegetables","children":[{"name":"Peas","value":"Peas","count":1}]},{"name":"Category 2","value":"Fruits","children":[{"name":"Apples","value":"Apples","count":3},{"name":"Bananas","value":"Bananas","count":2}]},{"name":"Category 3","value":"Desserts","children":[]}]; let createObject = (arr) => arr.reduce((op,[key,value])=>{ op[key] = value return op },{}) let arr2Obj = createObject(arr2.map(val => [val.name, val])) const res = arr1.map(({ name, value, children }) => { let arr2Children = ( arr2Obj[name] || {} ).children let childrenObj = createObject(arr2Children.map(val => [val.name,val])) let newChildren = children.map( val => { let count = (childrenObj[val.name] || {}).count || 0 return {...val,count} }) return {name,value,children:newChildren} }); console.log(res); 

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM