48

Imagine I have an array:

A = Array(1, 2, 3, 4, 5, 6, 7, 8, 9);

And I want it to convert into 2-dimensional array (matrix of N x M), for instance like this:

A = Array(Array(1, 2, 3), Array(4, 5, 6), Array(7, 8, 9));

Note, that rows and columns of the matrix is changeable.

Mr. Polywhirl
  • 42,981
  • 12
  • 84
  • 132
Bakhtiyor
  • 7,198
  • 15
  • 55
  • 77
  • 2
    `Array.prototype.toMatrix=function(per){return this.reduce(function(prev,current,i){if(i%per==0)prev.push([current]);else prev[prev.length-1].push(current);return prev;},[])}` – Nick Manning Dec 09 '15 at 21:36
  • `const chunk = (xs, n) => xs.length < n ? [xs] : [xs .slice (0, n), ... chunk (xs .slice (n), n)]` – Scott Sauyet Mar 18 '20 at 21:13
  • See duplicate: [_"Convert a 1D array to 2D array"_](https://stackoverflow.com/questions/22464605/convert-a-1d-array-to-2d-array) for more responses. – Mr. Polywhirl Apr 27 '21 at 15:56

19 Answers19

69

Something like this?

function listToMatrix(list, elementsPerSubArray) {
    var matrix = [], i, k;

    for (i = 0, k = -1; i < list.length; i++) {
        if (i % elementsPerSubArray === 0) {
            k++;
            matrix[k] = [];
        }

        matrix[k].push(list[i]);
    }

    return matrix;
}

Usage:

var matrix = listToMatrix([1, 2, 3, 4, 4, 5, 6, 7, 8, 9], 3);
// result: [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
jwueller
  • 30,582
  • 4
  • 66
  • 70
44

You can use the Array.prototype.reduce function to do this in one line.

ECMAScript 6 style:

myArr.reduce((rows, key, index) => (index % 3 == 0 ? rows.push([key]) 
  : rows[rows.length-1].push(key)) && rows, []);

"Normal" JavaScript:

myArr.reduce(function (rows, key, index) { 
  return (index % 3 == 0 ? rows.push([key]) 
    : rows[rows.length-1].push(key)) && rows;
}, []);

You can change the 3 to whatever you want the number of columns to be, or better yet, put it in a reusable function:

ECMAScript 6 style:

const toMatrix = (arr, width) => 
    arr.reduce((rows, key, index) => (index % width == 0 ? rows.push([key]) 
      : rows[rows.length-1].push(key)) && rows, []);

"Normal" JavaScript:

function toMatrix(arr, width) {
  return arr.reduce(function (rows, key, index) { 
    return (index % width == 0 ? rows.push([key]) 
      : rows[rows.length-1].push(key)) && rows;
  }, []);
}
Banciur
  • 75
  • 6
samanime
  • 25,408
  • 15
  • 90
  • 139
  • Isn't it a good idea to avoid mutate the "rows" array? const toMatrix = (arr, width) => arr.reduce((rows, key, index) => (index % width === 0) ? [...rows, [key]] : [...rows.slice(0,-1), [...rows[rows.length -1], key]], []); – Mikou Jul 09 '18 at 08:24
  • 2
    In the `reduce()` function, the first parameter of the callback is the value you will be returning. There is no harm in mutating it because it was made new just for this (initialized with the second parameter of `reduce()`). There is no need for the extra overhead of avoiding mutations on it (in fact, mutating is probably more performant). It still qualifies as "functional" programming. – samanime Jul 10 '18 at 01:37
13

This code is generic no need to worry about size and array, works universally

  function TwoDimensional(arr, size) 
    {
      var res = []; 
      for(var i=0;i < arr.length;i = i+size)
      res.push(arr.slice(i,i+size));
      return res;
    }
  1. Defining empty array.
  2. Iterate according to the size so we will get specified chunk.That's why I am incrementing i with size, because size can be 2,3,4,5,6......
  3. Here, first I am slicing from i to (i+size) and then I am pushing it to empty array res.
  4. Return the two-dimensional array.
Zippy
  • 1,804
  • 5
  • 27
  • 36
6

The cleanest way I could come up with when stumbling across this myself was the following:

const arrayToMatrix = (array, columns) => Array(Math.ceil(array.length / columns)).fill('').reduce((acc, cur, index) => {
  return [...acc, [...array].splice(index * columns, columns)]
}, [])

where usage would be something like

const things = [
  'item 1', 'item 2',
  'item 1', 'item 2',
  'item 1', 'item 2'
]

const result = arrayToMatrix(things, 2)

where result ends up being

[
  ['item 1', 'item 2'],
  ['item 1', 'item 2'],
  ['item 1', 'item 2']
]
Calle Bergström
  • 480
  • 4
  • 12
4

How about something like:

var matrixify = function(arr, rows, cols) {
    var matrix = [];
    if (rows * cols === arr.length) {
        for(var i = 0; i < arr.length; i+= cols) {
            matrix.push(arr.slice(i, cols + i));
        }
    }

    return matrix;
};

var a = [0, 1, 2, 3, 4, 5, 6, 7];
matrixify(a, 2, 4);

http://jsfiddle.net/andrewwhitaker/ERAUs/

Andrew Whitaker
  • 124,656
  • 32
  • 289
  • 307
3

This a simple way to convert an array to a two-dimensional array.

function twoDarray(arr, totalPerArray) {
  let i = 0;
  let twoDimension = []; // Store the generated two D array
  let tempArr = [...arr]; // Avoid modifying original array

  while (i < arr.length) {
    let subArray = []; // Store 2D subArray

    for (var j = 0; j < totalPerArray; j++) {
      if (tempArr.length) subArray.push(tempArr.shift());
    }

    twoDimension[twoDimension.length] = subArray;
    i += totalPerArray;
  }
  return twoDimension;
}
const arr = [1, 2, 3, 4, 5, 6, 7, 8, 9];

twoDarray(arr, 3); // [ [ 1, 2, 3 ], [ 4, 5, 6 ], [ 7, 8, 9 ] ]
p8ul
  • 2,212
  • 19
  • 19
  • Please do not code like this. It is very hard to see what's going on and the code is not reusable nor universal. I'd suggest taking a look at the other solutions presented here to see how they work. – Roy Prins Jan 28 '21 at 10:41
  • Hi @RoyPrins. I have revised the answer to include a more reusable function. TY – p8ul Jan 31 '21 at 14:51
  • Good show! You even caught the bit where you modified the original array. – Roy Prins Feb 01 '21 at 19:43
2

Simply use two for loops:

var rowNum = 3;
var colNum = 3;
var k = 0;
var dest = new Array(rowNum);

for (i=0; i<rowNum; ++i) {
  var tmp = new Array(colNum);
  for (j=0; j<colNum; ++j) {
    tmp[j] = src[k];
    k++;
  }
  dest[i] = tmp;
}
Vincent Mimoun-Prat
  • 28,208
  • 16
  • 81
  • 124
2
function matrixify( source, count )
{
    var matrixified = [];
    var tmp;
    // iterate through the source array
    for( var i = 0; i < source.length; i++ )
    {
        // use modulous to make sure you have the correct length.
        if( i % count == 0 )
        {
            // if tmp exists, push it to the return array
            if( tmp && tmp.length ) matrixified.push(tmp);
            // reset the temporary array
            tmp = [];
        }
        // add the current source value to the temp array.
        tmp.push(source[i])
    }
    // return the result
    return matrixified;
}

If you want to actually replace an array's internal values, I believe you can call the following:

source.splice(0, source.length, matrixify(source,3));
cwallenpoole
  • 79,954
  • 26
  • 128
  • 166
1
function changeDimension(arr, size) {  
  var arrLen = arr.length;
  var newArr = [];
  var count=0;
  var tempArr = [];

  for(var i=0; i<arrLen; i++) {
    count++;
    tempArr.push(arr[i]);

    if (count == size || i == arrLen-1) {
      newArr.push(tempArr);
      tempArr = [];
      count = 0;
    }    
  }  
  return newArr;
}

changeDimension([0, 1, 2, 3, 4, 5], 4);
  • Can you explain what is happening in the if (count == size || i == arrLen-1) {...} - what happens when i == arrLen-1? – James Brown May 08 '17 at 04:15
1
function matrixify(array, n, m) {
    var result = [];
    for (var i = 0; i < n; i++) {
        result[i] = array.splice(0, m);
    }
    return result;
}
a = matrixify(a, 3, 3);
Jannic Beck
  • 2,385
  • 21
  • 30
1
function chunkArrToMultiDimArr(arr, size) {

    var newArray = [];

    while(arr.length > 0)
    {
      newArray.push(arr.slice(0, size));
      arr = arr.slice(size);
    }

  return newArray;
}

//example - call function
chunkArrToMultiDimArr(["a", "b", "c", "d"], 2);
SayedRakib
  • 181
  • 1
  • 2
  • 10
1

you can use push and slice like this

var array = [1,2,3,4,5,6,7,8,9] ;
var newarray = [[],[]] ;
newarray[0].push(array) ;
console.log(newarray[0]) ;

output will be

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

if you want divide array into 3 array

var array = [1,2,3,4,5,6,7,8,9] ;
var newarray = [[],[]] ;
newarray[0].push(array.slice(0,2)) ;
newarray[1].push(array.slice(3,5)) ;
newarray[2].push(array.slice(6,8)) ;

instead of three lines you can use splice

while(array.length) newarray.push(array.splice(0,3));
cooogeee
  • 181
  • 1
  • 10
1
const x: any[] = ['abc', 'def', '532', '4ad', 'qwe', 'hf', 'fjgfj'];

// number of columns
const COL = 3;

const matrix = array.reduce((matrix, item, index) => {
  if (index % COL === 0) {
    matrix.push([]);
  }

  matrix[matrix.length - 1].push(item);  

  return matrix;
}, [])

console.log(matrix);
Daomtthuan
  • 19
  • 3
1

Using the Array grouping proposal (currently stage 3), you can now also do something like the following:

function chunkArray(array, perChunk) {
  return Object.values(array.group((_, i) => i / perChunk | 0));
}

See also the MDN documentation for Array.prototype.group().

0

Simplest way with ES6 using Array.from()

const matrixify = (arr, size) => 
Array.from({ length: Math.ceil(arr.length / size) }, (v, i) =>  
arr.slice(i * size, i * size + size));
const list =  [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12] ;
console.log(matrixify(list, 3));
Selvam Elumalai
  • 693
  • 7
  • 22
Jayesh Vachhani
  • 101
  • 1
  • 1
0

Another stab at it,

  1. Creating an empty matrix (Array of row arrays)
  2. Iterating arr and assigning to matching rows

 function arrayToMatrix(arr, wantedRows) {
      // create a empty matrix (wantedRows Array of Arrays] 
      // with arr in scope
      return new Array(wantedRows).fill(arr)
        // replace with the next row from arr 
        .map(() => arr.splice(0, wantedRows))
    }

    // Initialize arr
    arr = new Array(16).fill(0).map((val, i) => i)

    // call!!
    console.log(arrayToMatrix(arr, 4));

    // Trying to make it nice
    const arrToMat = (arr, wantedRows) => new Array(wantedRows).fill(arr)
      .map(() => arr.splice(0, wantedRows))

(like in: this one)

(and: this one from other thread)

MatArray Class?

Extending an Array to add to a prototype, seems useful, it does need some features to complement the Array methods, maybe there is a case for a kind of MatArray Class? also for multidimensional mats and flattening them, maybe, maybe not..

Ron Erlih
  • 121
  • 3
  • 6
0

1D Array convert 2D array via rows number:

function twoDimensional(array, row) {
    let newArray = [];
    let arraySize = Math.floor(array.length / row);
    let extraArraySize = array.length % row;
    while (array.length) {
      if (!!extraArraySize) {
        newArray.push(array.splice(0, arraySize + 1));
        extraArraySize--;
      } else {
        newArray.push(array.splice(0, arraySize));
      }
    }

    return newArray;
  }

 function twoDimensional(array, row) {
    let newArray = [];
    let arraySize = Math.floor(array.length / row);
    let extraArraySize = array.length % row;
    while (array.length) {
      if (!!extraArraySize) {
        newArray.push(array.splice(0, arraySize + 1));
        extraArraySize--;
      } else {
        newArray.push(array.splice(0, arraySize));
      }
    }

    return newArray;
  }
  
  console.log(twoDimensional([1,2,3,4,5,6,7,8,9,10,11,12,13,14], 3))
MD Ashik
  • 9,117
  • 10
  • 52
  • 59
-1

Short answer use:

const gridArray=(a,b)=>{const d=[];return a.forEach((e,f)=>{const 
h=Math.floor(f/b);d[h]=d[h]||[],d[h][f%b]=a[f]}),d};

Where:

a: is the array
b: is the number of columns
Mustafa Dwaikat
  • 3,392
  • 9
  • 27
  • 41
-2

An awesome repository here .

  • api : masfufa.js

  • sample : masfufa.html

According to that sample , the following snippet resolve the issue :

  jsdk.getAPI('my');
  var A=[1, 2, 3, 4, 5, 6, 7, 8, 9];
  var MX=myAPI.getInstance('masfufa',{data:A,dim:'3x3'});

then :

MX.get[0][0]  // -> 1 (first)
MX.get[2][2] //  ->9 (last)
Abdennour TOUMI
  • 87,526
  • 38
  • 249
  • 254