-1

Info: My problem is already solved. The answer from @kennarddh broke my mental block. Please go on if you are still interested.

Consider the following array:

const data = [
    ['A', 'B', 'C', ''],
    ['D', 'E', 'F', 'G']
]

How would you merge each column of each row together into a new array with just one row using newline character?

Expected output:

const result = [
    ['A\nD', 'B\nE', 'C\nF', '\nG']
]

For a better understanding of what this is all about. I have several excel files with my data in it. Most of them are formatted equal but some are not. To find my data in a file if it is not formatted as expected. I use fuzzy search to find the relevant cells on a sheet. But Fuse.js expects string lists to search in it. Therefore I have to convert the cell structure into a one dimensional list of strings. Because humans are lazy some data headers are stretching across two or more rows. Especially if some headers describe similar data like "price with vat" or "price without vat":

const fileData = [
    [],
    ['some', 'irrelevant', 'data']
    [''],
    ['', '', 'vat'],               // <-- start of headers
    ['product', 'price', 'price'], // <-- end of headers
    ['data', 'data', 'data'],      // <-- start of data
    ['data', 'data', 'data'],      // <-- end of data
    [''],
]

In cases like this searching only for the header:

'price'

would return two results. Which could not be differentiated from each other.

Merging the two or more header rows together using newlines instead:

const merged = [
    ['\nproduct', '\nprice', 'vat\nprice']
]

Would give a unique list of headers which could be differentiated. The fileData needs to be packed accordingly to be searched.

Given the relevant data headers from a config file I prepared. I could than search for:

'\nprice' 

or

'vat\nprice'

to get the column position of that header. Now I have a pretty good assumption that I'm importing the correct data from the correct position in a file.

kiroshiro
  • 113
  • 8
  • Loop through it and merge? – gre_gor Aug 17 '22 at 08:41
  • What todo about the last item? First row is shorter then the last one. And what about rows with other column counts? My guess first I need the correct column count. And so on. But I hoped someone else has done this problem already. – kiroshiro Aug 17 '22 at 08:46
  • 1
    This is _not_ a duplicate of the above mentioned answer, mainly because the `zip` _stops at the end of the shortest sublist_, whereas the OP needs a solution that _continues to the end of the longest sublist_ even if shorter sublists have been exhausted. Therefor a `zip` equivalent does _not_ work here. – David Aug 17 '22 at 09:16
  • @kiroshiro, look for `zip_longest` in the answers on the duplicate. – ChrisGPT was on strike Aug 21 '22 at 17:29
  • I'm not stuck. The answer from @kennarddh was exactly what I needed. I accepted the answer, too. I do not know why there is still an issue with the duplicate. Because I agree that it's not. – kiroshiro Aug 23 '22 at 12:54

2 Answers2

2

const merge2DArray = arr => {
  return arr.reduce((acc, secondData) => {
    if (acc.length < secondData.length) {
      const loopTimes = secondData.length - acc.length
      for (let i = 0; i < loopTimes; i++) {
        acc.push('')
      }
    }

    secondData.map((value, index) => {
      acc[index] += value
    })

    return acc
  }, [])
}

const data = [
  ['A', 'B', 'C'],
  ['D', 'E', 'F', 'G'],
]

const expected = ['AD', 'BE', 'CF', 'G']


console.log(merge2DArray(data))
console.log(expected)
kennarddh
  • 2,186
  • 2
  • 6
  • 21
0

You need to loop through the first one and check if the second one is bigger, if it is procede to add the value like:

const data = [
  ['A', 'B', 'C'],
  ['D', 'E', 'F', 'G']
];
let newArr = [];
const countFirstArr = data[0].length;
const countSecondArr = data[1].length;
data[0].forEach((el, index) => {
  newArr.push(el + data[1][index]);
});
if (countFirstArr < countSecondArr) {
  for (let i = countFirstArr; i < countSecondArr; i++) {
    newArr.push(data[1][i]);
  }
}
console.log(newArr);
Simone Rossaini
  • 8,115
  • 1
  • 13
  • 34