0

Before marking this as answered by another question please note this is an array of arrays, not a flat array, also, the number I have given are an example, I have just shown them so you can visually see what is happening.

I am trying to loop through an array of arrays. I have the following array:-

[
   [1, 2, 3, 4, 5, 6, 7, 8, 9],
   [1, 2, 3, 4, 5, 6, 7, 8, 9],
   [1, 2, 3, 4, 5, 6, 7, 8, 9],
   [3, 2, 1, 6, 5, 4, 9, 8, 7],
   [6, 5, 4, 9, 8, 7, 3, 2, 1],
   [7, 8, 9, 3, 2, 1, 6, 5, 4]
]

How is it possible to transform this array into chunks of 3x3 for example:-

[
   [1, 2, 3, 1, 2, 3, 1, 2, 3],
   [4, 5, 6, 4, 5, 6, 4, 5, 6],
   [7, 8, 9, 7, 8, 9, 7, 8, 9],
   [3, 2, 1, 6, 5, 4, 9, 8, 7],
   [6, 5, 4, 9, 8, 7, 3, 2, 1],
   [7, 8, 9, 3, 2, 1, 6, 5, 4],
]

As you can see from the array above I have chunked it using the first 3 values from each array and then by the 2nd 3n from each array and lastly the final 3n from each array.

So the array would be chunked like the following:-

1 2 3 | 4 5 6 | 7 8 9
1 2 3 | 4 5 6 | 7 8 9
1 2 3 | 4 5 6 | 7 8 9
---------------------
3 2 1 | 6 5 4 | 9 8 7
6 5 4 | 9 8 7 | 3 2 1
7 8 9 | 3 2 1 | 6 5 4

I have tried to loop through each line and resetting the column count when it hits an increment and increasing the row but this didn't work.

I can update the question with previous attempts if this is of any help? Also just a note, the array will be different sizes but always divisible by a particular number, for the above example I have chosen the number 3.

I have updated the question with more information. The array of arrays will always be divisible by a specific number, this example shows a divisible number of 3.

Web Nexus
  • 1,150
  • 9
  • 28
  • 1
    Please post your best attempt at solving it. – Barmar Jan 03 '22 at 21:39
  • Once you've chunked each nested array, you should be able to loop through them and concatenate corresponding elements of each. – Barmar Jan 03 '22 at 21:40
  • Will the lenght of the outer array also be divisible by the chunk size? – pilchard Jan 03 '22 at 22:07
  • 1
    @pilchard Yes sorry for the initial confusion, I have updated the question. the initial array will always be divisible buy the chunk size. my chunk size is 20 but the chunk size here for an example is 3 for easy of examples. – Web Nexus Jan 03 '22 at 22:09

2 Answers2

1

This can be solved with a chunk as per this question Split array into chunks combined with a zip as per this Javascript equivalent of Python's zip function

This has the benefit of being able to reverse the operation to get back to the original.

/** @see: https://stackoverflow.com/questions/8495687/split-array-into-chunks */
function chunk(array, chunk) {
    let result = [];
    for (let i = 0; i < array.length; i += chunk) {
        result.push(array.slice(i, i + chunk));
    }
    return result;
}

/** @see: https://stackoverflow.com/questions/4856717/javascript-equivalent-of-pythons-zip-function */
function zip(...rows) {
    return [...rows[0]].map((_, c) => rows.map((row) => row[c]));
}

const array = [
    [1, 2, 3, 4, 5, 6, 7, 8, 9],
    [1, 2, 3, 4, 5, 6, 7, 8, 9],
    [1, 2, 3, 4, 5, 6, 7, 8, 9],
    [3, 2, 1, 6, 5, 4, 9, 8, 7],
    [6, 5, 4, 9, 8, 7, 3, 2, 1],
    [7, 8, 9, 3, 2, 1, 6, 5, 4],
];

const result = chunk(array, 3)
    .flatMap((innerChunk) =>
        zip(...innerChunk.map((arr) => chunk(arr, 3)))
        .map((arr) => arr.flat())
    );

console.log(result.map((a) => a.join(', ')));

// Allows the result to be reverted to the original
const reversed = chunk(result, 3)
    .flatMap((innerChunk) =>
        zip(...innerChunk.map((arr) => chunk(arr, 3)))
        .map((arr) => arr.flat())
    );

console.log(reversed.map((a) => a.join(', ')));
pilchard
  • 12,414
  • 5
  • 11
  • 23
  • The issue with this is if the array have more lines for example 6 it will get all the first 3 values and push them into ```result[0]``` I will update my question, sorry. – Web Nexus Jan 03 '22 at 21:57
  • Edited. It's still just chunk/zip, but you need to chunk the outer array first. – pilchard Jan 03 '22 at 22:15
  • Amazing, thank you. I'm just going to pop in a huge array in JSFIddle and update the chunk size to see if it works nicely. – Web Nexus Jan 03 '22 at 22:22
  • I have run a sample of 40k data points and this works amazingly. – Web Nexus Jan 03 '22 at 22:27
  • 1
    Glad it helped. Read through the linked questions, there are other options for each utility including implementations using generator functions that may be more efficient on larger inputs. – pilchard Jan 03 '22 at 22:29
0

You can do it with a nested loop, slicing the array each time based on the size of the outer array.

const arr = [
   [1, 2, 3, 4, 5, 6, 7, 8, 9],
   [1, 2, 3, 4, 5, 6, 7, 8, 9],
   [1, 2, 3, 4, 5, 6, 7, 8, 9]
];

let out = [];
for(let i in arr) { out.push([]);}

arr.forEach((e, i) => {
    let scale = e.length / arr.length;
    for(let j in arr)
    {
      out[j] = out[j].concat(e.slice(j * scale, j * scale + scale));
    }
});

console.log(out);

Here it is once more with your original array prior to your edit:

const arr = [
   [1, 3, 2, 5, 2, 4, 3, 6, 8],
   [1, 4, 3, 6, 7, 3, 6, 4, 5],
   [2, 4, 1, 4, 6, 3, 7, 9, 7]
];

let out = [];
for(let i in arr) { out.push([]);}

arr.forEach((e, i) => {
    let scale = e.length / arr.length;
    for(let j in arr)
    {
      out[j] = out[j].concat(e.slice(j * scale, j * scale + scale));
    }
});

console.log(out);
Liftoff
  • 24,717
  • 13
  • 66
  • 119
  • The only issue with this answer is if the array has more than one 3 lines, for example, if it has 6 the last 3 arrays from the output are empty. https://jsfiddle.net/zpLyg7xf/ – Web Nexus Jan 03 '22 at 21:53
  • My original answer assumed that your array had dimensions of `[i][i^2]`. I've updated my answer so it will now work as long as the dimensions are `[i][i*n]`. The behavior is undefined if the inner array length is not divisible by the outer array length. – Liftoff Jan 03 '22 at 22:13
  • Your question has changed so significantly since your original post that it may be worth asking a new question. – Liftoff Jan 03 '22 at 22:16