skip to Main Content

I am trying to merge two arrays on columns with similar data

I can get this to work if both arrays have the same length dimension, but how can I generalize my function to work if arrays have different lengths?

where either arrA or arrB could have the greater length

Thank you

what I get

[ [ 'age', 'AAA', 'name' ],
  [ 25, 'aaa', 'Alice' ],
  [ 30, 'bbb', 'Bob' ] ]

what I want

[
  [ 'age', 'AAA', 'name' ],
  [ 25, 'aaa', 'Alice' ],
  [ 30, 'bbb', 'Bob' ],
  [ 60, 'zzz', '' ] 
]

function mergeRowsLOOP_n() {
  const arrB = [
    ["id", "name"],
    [1, "Alice"],
    [2, "Bob"],
  ];

  const arrA = [
    ["age", "ID", "AAA"],
    [25, 1, "aaa"],
    [30, 2, "bbb"],
    [60, 5, "zzz"]
  ];

  let X = mergeRowsLOOP(arrA, arrB, "ID", "id");
  console.log(X)
}

//a= array1, b=array2
//aKey = Header for Matching of arra1, bKey = Header for Matching of arra2
//bColumns indices of postback columns of array2; bColumns=[] to postback ALL array2 columns
function mergeRowsLOOP(a, b, aKey, bKey, bColumns = []) {

  const bIdx = b[0].findIndex(s => s.toLowerCase() === bKey.toLowerCase());
  bColumns = (bColumns.length === 0) ? b : getColumns(b, [bIdx, ...bColumns]);

  const aIdx = a[0].findIndex(s => s.toLowerCase() === aKey.toLowerCase()),
    bColumnsIdx = bColumns[0].findIndex(s => s.toLowerCase() === bKey.toLowerCase()),
    mergedArray = [];
  console.log(bColumnsIdx)
  for (let rowA of a) {
    for (let rowB of bColumns) {
      if (rowA[aIdx].toString().toLowerCase() === rowB[bColumnsIdx].toString().toLowerCase()) {
        rowA = spliceNthPos(rowA, aIdx);
        rowB = spliceNthPos(rowB, bColumnsIdx);
        mergedArray.push(rowA.concat(rowB, ));
      }
    }
  };

  return mergedArray;
}

function spliceNthPos(row, n) {
  let i = row.length;
  while (i--) {
    i === n && row.splice(i, 1);
  }
  return row;
}

2

Answers


  1. I believe your goal is as follows.

    • You want to achieve the following conversion.

      • From

          const arrB = [
            ["id", "name"],
            [1, "Alice"],
            [2, "Bob"],
          ];
        
          const arrA = [
            ["age", "ID", "AAA"],
            [25, 1, "aaa"],
            [30, 2, "bbb"],
            [60, 5, "zzz"]
          ];
        
      • To

          [
            [ 'age', 'AAA', 'name' ],
            [ 25, 'aaa', 'Alice' ],
            [ 30, 'bbb', 'Bob' ],
            [ 60, 'zzz', '' ] 
          ]
        

    In this case, how about the following sample script?

    Sample script:

    const arrB = [
      ["id", "name"],
      [1, "Alice"],
      [2, "Bob"],
    ];
    
    const arrA = [
      ["age", "ID", "AAA"],
      [25, 1, "aaa"],
      [30, 2, "bbb"],
      [60, 5, "zzz"]
    ];
    
    const [[arrBhead, ...arrBvalues], [arrAhead, ...arrAvalues]] = [arrB, arrA];
    const [arrBIdIdx, arrAIdIdx] = [arrBhead, arrAhead].map(a => a.findIndex(e => e.toLowerCase() == "id"));
    const [arrBObj, arrAObj] = [[arrBvalues, arrBIdIdx], [arrAvalues, arrAIdIdx]].map(([a, b]) => new Map(a.map(e => [e.splice(b, 1)[0], e])));
    const temp = Array(arrBhead.length - 1).fill("");
    const newHead = [[arrAhead, arrAIdIdx], [arrBhead, arrBIdIdx]].flatMap(([a, b]) => (a.splice(b, 1), a));
    const res = [newHead, ...[...arrAObj].map(([k, v]) => [...v, ...(arrBObj.has(k) ? arrBObj.get(k) : temp)])];
    
    console.log(res);

    When the processes of arrB and arrA are separeted, it becomes as follows.

    const arrB = [
      ["id", "name"],
      [1, "Alice"],
      [2, "Bob"],
    ];
    
    const arrA = [
      ["age", "ID", "AAA"],
      [25, 1, "aaa"],
      [30, 2, "bbb"],
      [60, 5, "zzz"]
    ];
    
    // About arrB
    const [arrBhead, ...arrBvalues] = arrB;
    const arrBIdIdx = arrBhead.findIndex(e => e.toLowerCase() == "id");
    const arrBObj = new Map(arrBvalues.map(e => [e.splice(arrBIdIdx, 1)[0], e]));
    
    // About arrA
    const [arrAhead, ...arrAvalues] = arrA;
    const arrAIdIdx = arrAhead.findIndex(e => e.toLowerCase() == "id");
    const arrAObj = new Map(arrAvalues.map(e => [e.splice(arrAIdIdx, 1)[0], e]));
    
    // Merge
    const temp = Array(arrBhead.length - 1).fill("");
    const newHead = [[arrAhead, arrAIdIdx], [arrBhead, arrBIdIdx]].flatMap(([a, b]) => (a.splice(b, 1), a));
    const res = [newHead, ...[...arrAObj].map(([k, v]) => [...v, ...(arrBObj.has(k) ? arrBObj.get(k) : temp)])];
    
    console.log(res);

    When this script is run, the following result is obtained.

    [
      ["age","AAA","name"],
      [25,"aaa","Alice"],
      [30,"bbb","Bob"],
      [60,"zzz",""]
    ]
    

    References:

    Login or Signup to reply.
  2. An approach with an object and an array for empty columns.

    const
        mergeBy = tables => {
            const
                SPACER = '',
                empty = [],
                head = [],
                rows = {};
                
            tables.forEach(([table, key]) => {
                const
                    index = table[0].indexOf(key);
                        
                table.forEach(({ [index]: key, ...row }, i) => {
                    if (i) (rows[key] ??= [...empty]).push(...Object.values(row));
                    else head.push(...Object.values(row));
                });
                empty.push(...Array(table[0].length - 1).fill(SPACER));
            });
    
            return [head, ...Object.values(rows)].map(a => {
                while (a.length < empty.length) a.push(SPACER);
                return a;
            });
        },
        arrB = [["id", "name"], [1, "Alice"], [2, "Bob"], [4, 'Jane']],
        arrA = [["age", "ID", "AAA"], [25, 1, "aaa"], [30, 2, "bbb"], [60, 5, "zzz"]],
        result = mergeBy([[arrA, "ID"], [arrB, "id"]]);
    
    console.log(result);
    .as-console-wrapper { max-height: 100% !important; top: 0; }
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search