Search code examples
javascripttypescriptecmascript-2016

How to map an array base on other arrays without nested looping - JS/TS, ES6(7)?


I have 2 arrays.

const history = [
   { type: 'change', old: 1, new: 2 },
   { type: 'change', old: 3, new: 4 },
];

const contents = [
   { id: 1, info: 'infor1' },
   { id: 2, info: 'infor2' },
   { id: 3, info: 'infor3' },
   { id: 4, info: 'infor4' },
];

And the array in result

const detailHistory = [
   { type: 'change', old: { id: 1, info: 'infor1' }, new: { id: 2, info: 'infor2' } },
   { type: 'change', old: { id: 3, info: 'infor3' }, new: { id: 4, info: 'infor4' } },
];

How can I create detailHistory without nested looping from history and contents


Solution

  • First create a Map for the contents, so you can retrieve one of its objects by id. Once you have that, it comes down to mapping the history objects:

    const history = [
       { type: 'change', old: 1, new: 2 },
       { type: 'change', old: 3, new: 4 },
    ];
    
    const contents = [
       { id: 1, info: 'infor1' },
       { id: 2, info: 'infor2' },
       { id: 3, info: 'infor3' },
       { id: 4, info: 'infor4' },
    ];
    
    const contentsMap = new Map(contents.map(o => [o.id, o]));
    const result = history.map(o => ({
        ...o,
        old: contentsMap.get(o.old),
        new: contentsMap.get(o.new)
    }));
    
    console.log(result);

    Be aware that old and new will get object references to the original objects in contents... they are not copied. If this is undesired, then use a (shallow) copy at the moment you map them into the result:

    const history = [
       { type: 'change', old: 1, new: 2 },
       { type: 'change', old: 3, new: 4 },
    ];
    
    const contents = [
       { id: 1, info: 'infor1' },
       { id: 2, info: 'infor2' },
       { id: 3, info: 'infor3' },
       { id: 4, info: 'infor4' },
    ];
    
    const contentsMap = new Map(contents.map(o => [o.id, o]));
    const result = history.map(o => ({
        ...o,
        old: {...contentsMap.get(o.old)},
        new: {...contentsMap.get(o.new)}
    }));
    
    console.log(result);