1

I am facing one problem with array destructuring, Please read my questions-

This is array 1-

const Array1 = [
    {
        label: "Fashion",
        value: 1
    },
    {
        label: "Electronics",
        value: 2
    }
]

This is array2-

const Array2 = [
    {
        id: 1,
        values: [
            { value: "S", meta: "s" },
            { value: "M", meta: "m" },
            { value: "Xl", meta: "xl" },
        ]
    },
    {
        id: 2,
        values: [
            { value: "Red", meta: "red" },
            { value: "Yellow", meta: "yellow" },
            { value: "Green", meta: "green" },
        ]
    }
]

I have to combine this two array when Id(array2) matched to value(array1) and also change field label- like I need actually like this-

const Array3 = [
    {
        name: "Fashion",
        options: [
            { value: "S", label: "s" },
            { value: "M", label: "m" },
            { value: "Xl", label: "xl" },
        ]
    },
    {
        name: "Electronics",
        options: [
            { value: "Red", label: "red" },
            { value: "Yellow", label: "yellow" },
            { value: "Green", label: "green" },
        ]
    }
]

I have already tried in this way-

const Array3 = Array1.map((item) => {
    return {
        name: item.label,
        values: [],
        options: Array2.map((e: any) => {
            if (e.id === item.value) {
                return e.values.map((v: any) => {
                    return {
                        label: v.meta,
                        value: v.value
                    }
                })
            }
        })
    }
})

From this function I am getting - one extra field with undefined-

Please click to see

But it's not working. Please help me by giving a correction of my functions.

Md Ali
  • 217
  • 1
  • 2
  • 10
  • you are using Array3 as an iterator for your second loop, this looks lke an error ;) – Ji aSH Aug 29 '22 at 08:21
  • I update my questions. – Md Ali Aug 29 '22 at 08:23
  • I actually I write `Array2` in my code editor. But unfortunately it got `Array3` when placing my questions. That's why I update my questions. But my problems are still occurring. – Md Ali Aug 29 '22 at 08:25
  • It seems your requirement is that the options array in Array3 would be the same as values in Array2. So simply options: Array2.find(e => e.id === item.value).values would work. Hope it helps – long_hair_programmer Aug 29 '22 at 08:26
  • Yes, but `values` filed name have to be changed. – Md Ali Aug 29 '22 at 08:27
  • How can I do that. – Md Ali Aug 29 '22 at 08:28
  • `Array2.find(e => e.id === item.value).values` this will return `value` and `meta` field But I have to return it as `value` and `label` – Md Ali Aug 29 '22 at 08:28
  • Oh my bad I missed that. So, the reason why Array2.map doesn't work is that map function always returns the same number of elements as the array you run .map on. So adding a condition results in undefined elements when condition doesn't match. You can do this. Array2.find(e => e.id === item.value).values.map(v => { return { value: v.value, label: v.meta } }) – long_hair_programmer Aug 29 '22 at 08:31
  • Yes, yes, thanks. many many thanks. it working. Can place a answer. I want to accept your answer. – Md Ali Aug 29 '22 at 08:34
  • I'm glad it helped. Have posted the answer. Take a look at @Nina Scholz's answer too as it's more efficient – long_hair_programmer Aug 29 '22 at 08:41
  • Does this answer your question? [Merge two array of objects based on a key](https://stackoverflow.com/questions/46849286/merge-two-array-of-objects-based-on-a-key) – pilchard Aug 29 '22 at 09:05

3 Answers3

4

You could take an object for the names and map new objects with name instead of id as properties.

const
    array1 = [{ label: "Fashion", value: 1 }, { label: "Electronics", value: 2 }], 
    array2 = [{ id: 1, values: [ { value: "S", meta: "s" }, { value: "M", meta: "m" }, { value: "Xl", meta: "xl" }] }, { id: 2, values: [{ value: "Red", meta: "red" }, { value: "Yellow", meta: "yellow" }, { value: "Green", meta: "green" }] }],
    names = Object.fromEntries(array1.map(({ label, value }) => [value, label])),
    result = array2.map(({ id, values }) => ({
        name: names[id],
        options: values.map(({ meta: label, ...o }) => ({ ...o, label }))
    }));

console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
Nina Scholz
  • 376,160
  • 25
  • 347
  • 392
  • I would do the same. But i would use a Map for names obj. But I would like to know what delivers the better performance Map vs. Object.fromEntries ? – J1n Aug 29 '22 at 08:29
  • Please read my questions again. Here your function return `value` and `meta` in values field. But I have to return `value` and `label` in values. I have to change field name `meta` to `label`. – Md Ali Aug 29 '22 at 08:31
  • @MdAli, please see edit. – Nina Scholz Aug 29 '22 at 08:38
  • @J1n, both options are possible. actually, i think `object` is faster, but i might be wrong. – Nina Scholz Aug 29 '22 at 08:39
1

The reason why Array2.map doesn't work is that map function always returns the same number of elements as the array you run .map on. So adding a condition results in undefined elements when condition doesn't match. You can do this:

options: Array2.find(e => e.id === item.value).values.map(v => { 
  return { value: v.value, label: v.meta } 
})

While this works, I'd recommend taking a look at @Nina Scholz's answer too as it makes use of Object/Dictionary which is much more efficient than running .find on Array2. O(1) vs O(n). So, if you expect to have lots of elements in Array2 or run this quite frequently then the more efficient solution would help

0

Maybe this is what you want?

const Array3 = Array1.map(array1Item => {
    const foundIndex = Array2.findIndex(array2Item => array2Item.id === array1Item.value);
    if(foundIndex !== -1) {
        return {
            name: array1Item.label,
            options: Array2[foundIndex].values
        }    
    };
    
    return undefined;
});
console.log(Array3);
/** 
[{
name: "Fashion"
options: Array(3)
0: {value: 'S', meta: 's'}
1: {value: 'M', meta: 'm'}
2: {value: 'Xl', meta: 'xl'}
},{
name: "Electronics"
options: Array(3)
0: {value: 'Red', meta: 'red'}
1: {value: 'Yellow', meta: 'yellow'}
2: {value: 'Green', meta: 'green'}
}]
*/
blurk
  • 235
  • 2
  • 6
  • Please read my questions again. Here your function return `value` and `meta` in values field. But I have to return `value` and `label` in values. I have to change field name `meta` to `label`. – Md Ali Aug 29 '22 at 08:32