Alter leftJoin function from an a exact match to contains JavaScript/Google app script

I have the left join function, which combines two arrays of different dimensions by exact matching on columns.

function test() {
  let a =[
          ['aH1','aH2','aH3','aH4'],   
          ['a','B','c','d'],
          ['x','R','l','a'],
          ['t','R','g','m'],
          ['t','A','g','m']
         ];

  let b =[
          ['bH1','bH2','bH3'], 
          ['A','ZZ','XX'],
          ['R','YY','RR'],
          ['t','GG','QQ']
         ];

  const result = leftJoin(a, b, "aH2", "bH1")   
  console.log(result)
  
Which gives:
  result = [
            [ 'aH1', 'aH2', 'aH3', 'aH4', 'bH2', 'bH3' ],
            [ 'a', 'B', 'c', 'd', '', '' ],
            [ 'x', 'R', 'l', 'a', 'YY', 'RR' ],
            [ 't', 'R', 'g', 'm', 'YY', 'RR' ],
            [ 't', 'A', 'g', 'm', 'ZZ', 'XX' ] 
           ]
           
}

But what if the matching column of array b now has strings that contain the value to match on. 'H|A|1|L' contain A

let b =[
        ['bH1','bH2','bH3'], 
        ['H|A|1|L','ZZ','XX'],
        ['|D|K|R','YY','RR'],
        ['t|S|G','GG','QQ']
       ];

How to alter leftJoin to do this?

I am guessing it is done here

const temp = b.slice(1).reduce((r, items, i) => (r[items[bIndex]] = items, r), {});

But I do not understand reduce enough to get the correct solution

Matching Function:
(sorry, but I do not recall where I found this)

function leftJoin(a, b, akey, bkey) {
    akey = akey.toLowerCase();
    bkey = bkey.toLowerCase();
  
    const without = ([...array], index) => (array.splice(index, 1), array);
    const aIndex = a[0].findIndex(s => s.toLowerCase() === akey);
    const bIndex = b[0].findIndex(s => s.toLowerCase() === bkey);
    const temp   = b.slice(1).reduce((r, items, i) => (r[items[bIndex]] = items, r), {});
        
    return a.map((a, i) => [
        ...a,
        ...without(
                  i
                  ? temp[a[aIndex]] || Array(b[0].length).fill('')
                  : b[0],
                  bIndex
        )
    ]);
}

>Solution :

You could split the string and assign the value to each splitted value.

items[bIndex].split('|').forEach(key => r[key] = items);
function leftJoin(a, b, akey, bkey) {
    akey = akey.toLowerCase();
    bkey = bkey.toLowerCase();

    const without = ([...array], index) => (array.splice(index, 1), array);
    const aIndex = a[0].findIndex(s => s.toLowerCase() === akey);
    const bIndex = b[0].findIndex(s => s.toLowerCase() === bkey);
    const temp = b.slice(1).reduce((r, items, i) => {
          items[bIndex].split('|').forEach(key => r[key] = items);
          return r;        
        }, {});

    return a.map((a, i) => [
        ...a,
        ...without(i
            ? temp[a[aIndex]] || Array(b[0].length).fill('')
            : b[0],
          bIndex
        )
    ]);
}


function test() {
  let a = [
    ['aH1', 'aH2', 'aH3', 'aH4'],
    ['a', 'B', 'c', 'd'],
    ['x', 'R', 'l', 'a'],
    ['t', 'R', 'g', 'm'],
    ['t', 'A', 'g', 'm']
  ];

  let b = [
    ['bH1', 'bH2', 'bH3'],
    ['H|A|1|L', 'ZZ', 'XX'],
    ['|D|K|R', 'YY', 'RR'],
    ['t|S|G', 'GG', 'QQ']
  ];

  const result = leftJoin(a, b, "aH2", "bH1")
  result.forEach(a => console.log(...a));
}

test();
.as-console-wrapper { max-height: 100% !important; top: 0; }

Leave a Reply