简体   繁体   中英

Two arrays inner join in JavaScript

Following are the 2 arrays I have,

 var g= [ 
        { id: 36, name: 'AAA', goal: 'yes' },
        { id: 40, name: 'BBB', goal: 'yes' },
        { id: 39, name: 'JJJ', goal: 'yes' },
        { id: 27, name: 'CCC', goal: 'yes' }];

    var c= [ 
        { id: 36, color:"purple" },
        { id: 40, color:"purple" },
        { id: 100, color:"pink"} ];

Desired output(left join on 'id'):

    res = [{ id: 36, name: 'AAA', goal: 'yes' , color:"purple"}, { id: 40, name: 'BBB', goal: 'yes', color:"purple" }]

here's an existing logic which does merger but I'm looking for a logic for left join:

    function mergeBy(key, data) {
      return Array.from(data
          .reduce((m, o) => m.set(o[key], { ...m.get(o[key]), ...o }), new Map)
          .values()
      );
    }

Here are some joins for you, take your pick!

 function* innerJoin(a, b, key) { let idx = new Map(b.map(x => [key(x), x])); for (let x of a) { let k = key(x); if (idx.has(k)) yield {...x, ...idx.get(k)}; } } function* leftJoin(a, b, key) { let idx = new Map(b.map(x => [key(x), x])); for (let x of a) { let k = key(x); yield idx.has(k)? {...x, ...idx.get(k)}: x; } } function* rightJoin(a, b, key) { let idx = new Map(a.map(x => [key(x), x])); for (let x of b) { let k = key(x); yield idx.has(k)? {...idx.get(k), ...x}: x; } } // var A = [ {id: 1, a: 'a1'}, {id: 2, a: 'a2'}, {id: 7, a: 'a3'}, {id: 8, a: 'a4'} ]; var B = [ {id: 1, b: 'b1'}, {id: 2, b: 'b2'}, {id: 9, b: 'b3'} ]; console.log('INNER:') console.log(...innerJoin(A, B, x => x.id)) console.log('LEFT') console.log(...leftJoin(A, B, x => x.id)) console.log('RIGHT') console.log(...rightJoin(A, B, x => x.id))

What your expected results asks for is not a left join. You're asking for an inner join of g and c using id and to merge the properties. The below should do this

 var g= [ { id: 36, name: 'AAA', goal: 'yes' }, { id: 40, name: 'BBB', goal: 'yes' }, { id: 39, name: 'JJJ', goal: 'yes' }, { id: 27, name: 'CCC', goal: 'yes' }]; var c= [ { id: 36, color:"purple" }, { id: 40, color:"purple" }, { id: 100, color:"pink"} ]; function mergeBy(key, dataL, dataR) { const rMap = dataR.reduce((m, o) => m.set(o[key], {...m.get(o[key]), ...o }), new Map); return dataL.filter(x => rMap.get(x[key])).map(x => ({...x, ...rMap.get(x[key]) })); } console.log(mergeBy("id",g, c))

You can use Maps for joining two arrays. See the code snippet for three types of joins Left Join, Right Join, Inner Join.

All the three joins take O(N) time.

 const g = [ { id: 36, name: 'AAA', goal: 'yes', random: 27 }, { id: 40, name: 'BBB', goal: 'yes' }, { id: 39, name: 'JJJ', goal: 'yes' }, { id: 27, name: 'CCC', goal: 'yes', lag: '23.3343' }, ]; const c = [ { id: 36, name: 'AAA', goal: 'yes', color: 'purple' }, { id: 40, name: 'BBB', circle: 'yes', color: 'purple' }, { id: 100, name: 'JJJ', circle: 'yes' }, ]; const gMap = new Map(g.map(o => [o.id, o])); const cMap = new Map(c.map(o => [o.id, o])); const leftJoin = g.reduce( (a, o) => (cMap.has(o.id)? [...a, {...o, ...cMap.get(o.id) }]: [...a, o]), [] ); const rightJoin = c.reduce( (a, o) => (gMap.has(o.id)? [...a, {...o, ...gMap.get(o.id) }]: [...a, o]), [] ); const innerJoin = g.reduce( (a, o) => (cMap.has(o.id)? [...a, {...o, ...cMap.get(o.id) }]: a), [] ); console.log("LEFT JOIN\n", leftJoin) console.log("RIGHT JOIN\n", rightJoin) console.log("INNER JOIN\n", innerJoin)

You could get uncommon keys and filter the merged results with.

 const mergeCommon = (a, b, key) => { const aByKey = a.reduce((m, o) => m.set(o[key], o), new Map); return b.reduce((r, o) => { if (aByKey.has(o[key])) r.push({... aByKey.get(o[key]), ...o}); return r; }, []); }, g = [{ id: 36, name: 'AAA', goal: 'yes', 'random': 27 }, { id: 40, name: 'BBB', goal: 'yes' }, { id: 39, name: 'JJJ', goal: 'yes' }, { id: 27, name: 'CCC', goal: 'yes', lag: "23.3343" }], c = [{ id: 36, name: 'AAA', goal: 'yes', color:"purple" }, { id: 40, name: 'BBB', circle: 'yes', color:"purple" }, { id: 100, name: 'JJJ', circle: 'yes'}], result = mergeCommon(g, c, 'id'); console.log(result);
 .as-console-wrapper { max-height: 100%;important: top; 0; }

 var g = [ { id: 36, name: 'AAA', goal: 'yes', 'random':27}, { id: 40, name: 'BBB', goal: 'yes' }, { id: 39, name: 'JJJ', goal: 'yes' }, { id: 27, name: 'CCC', goal: 'yes', lag: "23.3343"} ]; var c = [ { id: 36, name: 'AAA', goal: 'yes', color:"purple" }, { id: 40, name: 'BBB', circle: 'yes', color:"purple" }, { id: 100, name: 'JJJ', circle: 'yes'} ]; const combinedArr = (arr1, arr2) => { //Filter the arr2 and find the only matching elements from the first array const filteredArr = arr2.filter(({id}) => arr1.some(({id: arr1Id}) => arr1Id === id)); //Loop through the filtered array and fetch the matching item from first and add obj from filtered array return filteredArr.map(obj => { return {...arr1.find(({id}) => id === obj.id), ...obj } }) } console.log(combinedArr(g, c));
 .as-console-wrapper { max-height: 100%;important; }

There you go, one liner

 var g= [ { id: 36, name: 'AAA', goal: 'yes' }, { id: 40, name: 'BBB', goal: 'yes' }, { id: 39, name: 'JJJ', goal: 'yes' }, { id: 27, name: 'CCC', goal: 'yes' }]; var c= [ { id: 36, color:"purple" }, { id: 40, color:"purple" }, { id: 100, color:"pink"} ]; const result = g.map(i =>..c.find(e => e.id === i.id) && ({.,.i. ...c.find(e => e.id === i;id)})).filter(Boolean); console.log(result);

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