Javascript map over two dimensional array
Asked Answered
F

4

6

I have this array:

rows = [ [ 89, 18, 9 ], [ 1903, 3, 4 ], [ 3, 1, 800 ] ];

It should look like this:

[ [ 89, 1903, 3 ], [ 18, 3, 1 ], [ 9, 4, 800 ] ]

And the code, that is working, looks like this:

rows[0].map((_, columnIndex) => rows.map(
            row => row[columnIndex])
        );

How does this work?

Fleuron answered 5/3, 2018 at 22:54 Comment(4)
The description for the 2d tag is 2D computer graphics is the computer-based generation of digital images—mostly from two-dimensional models. - totally not what you're talking aboutInterstellar
You're transposing your data structure, which only works with that code because it's square. Either way, perhaps you could explain which parts confuse you? Did you check up on what map does yet?Cutwater
I understand what map does, but i don't understand how the second chained map gets to the right array elements. Can you explain me that?Fleuron
@Cutwater Doesn't have to be square. It could be any rectangular array. It's just that the names of the variables are misleading. I'd rather write rows[0].map((_, columnIndex) => rows.map(row => row[columnIndex])).Standford
T
2
                  +--- The outter function map gets the first array to loop through the rows
[ 89,   18, 9   ] |
[ 1903, 3,  4   ] |
[ 3,    1,  800 ] v
  +--->
  |
  +- The nested function map is looping through the columns.
     The key here is the fixed column using index (column[index])
     from the outter function map, so every iteration from the outter
     function map will fix the access to that column, i.e -
     index = 0 will access the array as follow: array[j][0], array[j+1, 0], ... array[n, 0]
                                                         ^              ^                ^

This is an approach to illustrate what's happening using direct index accesses.

var rows = [ [ 89, 18, 9 ], [ 1903, 3, 4 ], [ 3, 1, 800 ] ];

var result = [];
for (var i = 0; i < rows[0].length; i++) {
  result[i] = new Array(rows[0].length).fill();

  for (var j = 0; j < rows.length; j++) {
    result[i][j] = rows[j][i]; // Here is the fixed column access using the outter index i.
  }
}

console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
Touchback answered 5/3, 2018 at 23:30 Comment(2)
Was just writing my own near identical answer. +1. My for loop was slightly different to yours though: for(var i = 0; i < rows[0].length; i++){ result.push([]); for(var j = 0; j < rows.length; j++){ result[result.length-1].push(rows[j][i]); } }Haygood
@Haygood yes, it was similar!Touchback
C
8

I'll assume you are simply not accustomed to the particular language features being used here, hence why you can't follow what is going on, so here goes:

  • Your structure is a nested Array. Hence the nested Array.maps.

  • Both map callbacks make use of implicit return.

which unfolds to this:

rows[0].map((row, index) => {
  return rows.map((column) => {
    return column[index]
  })
})

The 2 arguments passed to the map callback are the following:

  • element: The currently iterated Array element; In your first map this is the row argument.
  • i: The current iteration number, starting from 0; In your first map this is the index argument.

That's all there is to it. From then on you just follow the iterations and the values of each argument at each iteration.

Clink answered 5/3, 2018 at 23:10 Comment(0)
T
2
                  +--- The outter function map gets the first array to loop through the rows
[ 89,   18, 9   ] |
[ 1903, 3,  4   ] |
[ 3,    1,  800 ] v
  +--->
  |
  +- The nested function map is looping through the columns.
     The key here is the fixed column using index (column[index])
     from the outter function map, so every iteration from the outter
     function map will fix the access to that column, i.e -
     index = 0 will access the array as follow: array[j][0], array[j+1, 0], ... array[n, 0]
                                                         ^              ^                ^

This is an approach to illustrate what's happening using direct index accesses.

var rows = [ [ 89, 18, 9 ], [ 1903, 3, 4 ], [ 3, 1, 800 ] ];

var result = [];
for (var i = 0; i < rows[0].length; i++) {
  result[i] = new Array(rows[0].length).fill();

  for (var j = 0; j < rows.length; j++) {
    result[i][j] = rows[j][i]; // Here is the fixed column access using the outter index i.
  }
}

console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
Touchback answered 5/3, 2018 at 23:30 Comment(2)
Was just writing my own near identical answer. +1. My for loop was slightly different to yours though: for(var i = 0; i < rows[0].length; i++){ result.push([]); for(var j = 0; j < rows.length; j++){ result[result.length-1].push(rows[j][i]); } }Haygood
@Haygood yes, it was similar!Touchback
G
0

Iterator Methods (like map,forEach,filter...) dealing with array 2d as every element is 1d array

For example:

    arr= [[1,0,0],
          [0,1,0],
          [0,0,1]]
    arr.map( (item)=> {
           item.forEach( (element)=> {
             //...
            //...
           })
    })

The first iterator (map) take the first row in arr array in this example [1,0,0]

The second iterator takes the second row of arr that is [0,1,0] save it in item and so on...

In a nested loop (foreach) that take the real number like 0 or 1. Here the code can deal with it.

Gig answered 1/10, 2020 at 11:40 Comment(1)
This answer is a bit unclear for me. Save it in item? Here the code can deal with it? What does this mean?Juridical
W
0

Wrapping one's head around multi-dimensional arrays is confusing enough by itself (compare the comments above about square vs. non-square), but there's a bit more going on here than was previously explained.

Consider the inner part: rows.map( row => row[columnIndex] ). This is straightforward: for each row we extract the value in the specified column position, so this makes a 1-dimensional array representing a column in the original array ("rows") - e.g. if columnindex is 2 this returns [9, 4, 800]. Note that "rows" is being referenced here as a variable external to the map function, whereas "row" is just an internal name of the map function referring to the array element being processed, and the argument "columnIndex" is being passed in from the outer map() call.

Now the outer map function is being applied to the elements of rows[0] (and NOT to rows itself!), meaning it takes that first row (simply to determine how many columns there are!) and walks through it, disregarding the current value completely (that's why the generic underscore is used) and only caring about the current position in that array, i.e. the columnIndex. For each column index it will return the output of that inner map we just discussed.

To be clear, this works just fine on any rectangular array: if your original array had had 3 rows of 4 values each, the outer map would have walked through those 4 positions, and for each of them returned an array of 3 values extracted from the 3 rows at that given position, so the resulting array would have had 4 rows of 3 values each, perfectly transposing the original matrix.

Wadleigh answered 29/8 at 16:45 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.