115

I want to create a two dimensional array in Javascript where I'm going to store coordinates (x,y). I don't know yet how many pairs of coordinates I will have because they will be dynamically generated by user input.

Example of pre-defined 2d array:

var Arr=[[1,2],[3,4],[5,6]];

I guess I can use the PUSH method to add a new record at the end of the array.

How do I declare an empty two dimensional array so that when I use my first Arr.push() it will be added to the index 0, and every next record written by push will take the next index?

This is probably very easy to do, I'm just a newbie with JS, and I would appreciate if someone could write a short working code snippet that I could examine. Thanks

Zannix
  • 1,473
  • 3
  • 16
  • 26
  • Have you tried `var Arr = new Array(new Array());`? And yes, `push` and `pop` add or remove elements from the end of the array, while `shift` and `unshift` remove or add elements to the beginning of the array. – abiessu Aug 10 '13 at 15:15
  • This sounds like two different questions. First you want the arbitrary sized array. Then you're sortof asking a different question that involves the push method. (Also, if you want to answer your own question, I think it's best to do that in the answer section.) This is a top ranked question in Google for creating a multi-dimensional array in JavaScript, and I know Google doesn't dictate content here, but I'd say it's a fundamentally important question with a wide range of wacky answers. – PJ Brunet Jun 19 '17 at 05:31

23 Answers23

114

You can just declare a regular array like so:

var arry = [];

Then when you have a pair of values to add to the array, all you need to do is:

arry.push([value_1, value2]);

And yes, the first time you call arry.push, the pair of values will be placed at index 0.

From the nodejs repl:

> var arry = [];
undefined
> arry.push([1,2]);
1
> arry
[ [ 1, 2 ] ]
> arry.push([2,3]);
2
> arry
[ [ 1, 2 ], [ 2, 3 ] ]

Of course, since javascript is dynamically typed, there will be no type checker enforcing that the array remains 2 dimensional. You will have to make sure to only add pairs of coordinates and not do the following:

> arry.push(100);
3
> arry
[ [ 1, 2 ],
  [ 2, 3 ],
  100 ]
DJG
  • 6,413
  • 4
  • 30
  • 51
  • 1
    this seems like an elegant solution, so I got X and Y coordinates, and I insert them like so: arry.push([x,y]); - but how do I get back later, for example the x coordinate on index 0? – Zannix Aug 10 '13 at 15:30
  • 2
    You can just retrieve arry[0][0]. (And to get the Y coordinate, you can retrieve arry[0][1].) – DJG Aug 10 '13 at 15:34
108

If you want to initialize along with the creation, you can use fill and map.

const matrix = new Array(5).fill(0).map(() => new Array(4).fill(0));

5 is the number of rows and 4 is the number of columns.

AbhinavD
  • 6,892
  • 5
  • 30
  • 40
  • This works well in declarative contexts too, e.g. pre-allocation of a 2d array as an object member. Perhaps not something that one would design from scratch, but useful for tasks like porting from other languages. – steve.sims Oct 11 '18 at 06:13
  • 41
    Please also note that here `map(() => {})` is used to create a standalone row and it's necessary. The way of `new Array(5).fill(new Array(4).fill(0))` is a very dangerous move. Since all the rows are filled with references to ONE array, if you update `arr[0][0]` the value of `arr[1][0]` will be changed too. This may raise very serious and dark issues when you use this array as a cache table. – Kaihua Jan 24 '19 at 00:55
  • 2
    @Kaihua I am new to JavaScript but used the print format code supplied by Kamil Kiełczewski below and there is no problem with Abhinav's solution. If any element is modified, there are *no* changes to any other elements. I suppose that your comment is an analog of shallow copies in Python, but that is not the case here. – yamex5 Apr 30 '20 at 17:49
  • @Kaihua, I don't understand, how is this reference to the same array. If you create array of 5 elements (`new Array(5)`) and fill it with new created array (`new Array(4)`)?! Doesn't `new Array()` mean that you creating new array anymore?! What's wrong with JS?! – Rami Chasygov Aug 09 '20 at 13:02
  • 2
    @RamzanChasygov Languages can be impefect depending on the context =D – Kaihua Aug 23 '20 at 10:28
  • 1
    @RamazanChasygov The code may look counterintuitive at first glance, but it does behave exactly like it should. When you call `Array(5).fill(new Array(4))`, this will happen: `new Array(4)` will be called exactly **once**, and this newly created array (with length 4) will then be passed to the `fill` function. Though there's only a single object created in memory, and this single object will be used to *fill* all the array elements, i.e. all the array elements point to the same location in memory. – Benjamin M Mar 12 '22 at 22:44
72

ES6

Matrix m with size 3 rows and 5 columns (remove .fill(0) to not init by zero)

[...Array(3)].map(_=>Array(5).fill(0))       

let Array2D = (r,c) => [...Array(r)].map(_=>Array(c).fill(0));

let m = Array2D(3,5);

m[1][0] = 2;  // second row, first column
m[2][4] = 8;  // last row, last column

// print formated array
console.log(JSON.stringify(m)
  .replace(/(\[\[)(.*)(\]\])/g,'[\n  [$2]\n]').replace(/],/g,'],\n  ')
);
Kamil Kiełczewski
  • 85,173
  • 29
  • 368
  • 345
  • @AndrewBenjamin - where exactly is the problem - can you describe it or provide test case? – Kamil Kiełczewski Dec 22 '18 at 00:38
  • Well I copied your code and it threw errors when I tried to access values randomly in the array. However, one tiny modification and it worked: Array(n + 1).fill(Array(m+1).fill(0)) – AndrewBenjamin Dec 22 '18 at 01:27
  • And since you sent me in the right direction and I like your style ... upvote ... though not sure why you code as-is didn't quite work for me. Ignoring the typescript casting, the only modfication is 'fill' instead of 'map' – AndrewBenjamin Dec 22 '18 at 01:29
  • I think I know what went wrong, I accidentally cast the first array as instead of after copy-pasting your script. So my bad. – AndrewBenjamin Dec 22 '18 at 01:55
  • 1
    Regarding the fill method, take into account that => "If the first parameter is an object, each slot in the array will reference that object." Therefore if you do this [...Array(r)].map(x=>Array(c).fill({ x: ..., y: ... })) you will have the same object per row in your matrix – Natalia Duran Mar 08 '22 at 20:38
  • why do we need to destructure [...Array(3)] ? – Akshay Vijay Jain Nov 15 '22 at 14:46
  • 1
    @AkshayVijayJain because `map` will not work as we expected on empty array - but answer to this question in details goes beyond the OP question. Ask separate question or find it on SO. – Kamil Kiełczewski Nov 15 '22 at 16:56
  • https://stackoverflow.com/questions/74449747/why-do-we-need-to-destructure-array-to-get-a-multi-dimensional-array – Akshay Vijay Jain Nov 15 '22 at 17:19
37

If you want to be able access the matrix like so:

matrix[i][j]

I find it the most convenient to init it in a loop.

var matrix = [],
    cols = 3;

//init the grid matrix
for ( var i = 0; i < cols; i++ ) {
    matrix[i] = []; 
}

This will give you

[ [], [], [] ]

so

matrix[0][0]
matrix[1][0]

returns undefined and not the error "Uncaught TypeError: Cannot set property '0' of undefined".

Benjamin W.
  • 46,058
  • 19
  • 106
  • 116
Lorenzo Gangi
  • 601
  • 7
  • 8
16

You can nest one array within another using the shorthand syntax:

   var twoDee = [[]];
Kevin Bowersox
  • 93,289
  • 19
  • 159
  • 189
7

You can try something like this:-

var arr = new Array([]);

Push data:

arr[0][0] = 'abc xyz';
Rahul Tripathi
  • 168,305
  • 31
  • 280
  • 331
6

This one should work:

const arr = new Array(5).fill().map(_ => new Array(5).fill(0)) // ✅

You may ask why did I use map instead of:

const badArr = new Array(5).fill(new Array(5).fill(0)) // ❌

The problem with the example above is that it adds references to the array that was passed into the fill method:

enter image description here

While this one works fine:

enter image description here

codelover1
  • 135
  • 2
  • 7
4

An empty array is defined by omitting values, like so:

v=[[],[]]
a=[]
b=[1,2]
a.push(b)
b==a[0]
UIlrvnd
  • 786
  • 6
  • 20
4

You can fill an array with arrays using a function:



var arr = [];
var rows = 11;
var columns = 12;

fill2DimensionsArray(arr, rows, columns);

function fill2DimensionsArray(arr, rows, columns){
    for (var i = 0; i < rows; i++) {
        arr.push([0])
        for (var j = 0; j < columns; j++) {
            arr[i][j] = 0;
        }
    }
}

The result is:



Array(11)
0:(12) [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
1:(12) [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
2:(12) [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
3:(12) [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
4:(12) [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
5:(12) [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
6:(12) [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
7:(12) [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
8:(12) [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
9:(12) [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
10:(12)[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]

entoniperez
  • 544
  • 5
  • 14
4

One Liner

let m = 3 // rows
let n = 3 // columns
let array2D = Array(m).fill().map(entry => Array(n))

This implementation creates a unique subarray for each entry. So setting array2D[0][1] = 'm' does not set each entry's [1] index to 'm'

Mark Schultheiss
  • 32,614
  • 12
  • 69
  • 100
sharkk22
  • 353
  • 3
  • 7
  • 1
    let array2D = Array(3).fill().map(entry => Array(3)) there it is in one –  Jul 30 '21 at 16:30
3

I know this is an old thread but I'd like to suggest using an array of objects rather than an array of arrays. I think it make the code simpler to understand and update.

// Use meaningful variable names like 'points', 
// anything better than a bad pirate joke, 'arr'!
var points = [];

// Create an object literal, then add it to the array
var point = {x: 0, y: 0};
points.push(point);

// Create and add the object to the array in 1 line
points.push({x:5, y:5});

// Create the object from local variables 
var x = 10;
var y = 8;
points.push({x, y});

// Ask the user for a point too
var response = prompt("Please enter a coordinate point. Example: 3,8");
var coords = response.split(",").map(Number);
points.push({x: coords[0], y: coords[1]});

// Show the results
var canvas = document.getElementById('graph');
var painter = canvas.getContext("2d");
var width = canvas.width, height = canvas.height;
var scale = 10, radius = 3.5, deg0 = 0, deg360 = 2 * Math.PI;

painter.beginPath();
for (var point of points) {
    var x = point.x * scale + scale;
    var y = height - point.y * scale - scale;
    painter.moveTo(x + radius, y);
    painter.arc(x, y, radius, deg0, deg360);
    painter.fillText(`${point.x}, ${point.y}`, x + radius + 1, y + radius + 1);
}
painter.stroke();
<canvas id="graph" width="150" height="150" style="border: 1px solid red;"></canvas>
sdphm80
  • 41
  • 1
2
const grid = Array.from(Array(3), e => Array(4));

Array.from(arrayLike, mapfn)

mapfn is called, being passed the value undefined, returning new Array(4).

An iterator is created and the next value is repeatedly called. The value returned from next, next().value is undefined. This value, undefined, is then passed to the newly-created array's iterator. Each iteration's value is undefined, which you can see if you log it.

var grid2 = Array.from(Array(3), e => {
  console.log(e); // undefined
  return Array(4); // a new Array.
});
Garrett
  • 2,936
  • 1
  • 20
  • 22
  • Please add some description how and why this is working. Your answer should allow other users to learn from. – david Apr 02 '20 at 13:16
  • And if you want to initialize the array to a specific value like 0: `const grid = Array.from(Array(3), () => Array(4).fill(0))`. – Ludovic Kuty Jun 24 '21 at 12:55
2

ES6

const rows = 2;
const columns = 3;

const matrix = [...Array(rows)].map(() => [...Array(columns)].fill(0));

console.log(matrix);
Vinay Sharma
  • 3,291
  • 4
  • 30
  • 66
1

Create an object and push that object into an array

 var jSONdataHolder = function(country, lat, lon) {

    this.country = country;
    this.lat = lat;
    this.lon = lon;
}

var jSONholderArr = [];

jSONholderArr.push(new jSONdataHolder("Sweden", "60", "17"));
jSONholderArr.push(new jSONdataHolder("Portugal", "38", "9"));
jSONholderArr.push(new jSONdataHolder("Brazil", "23", "-46"));

var nObj = jSONholderArr.length;
for (var i = 0; i < nObj; i++) {
   console.log(jSONholderArr[i].country + "; " + jSONholderArr[i].lat + "; " + 
   jSONholderArr[i].lon);

}
Björn Hallström
  • 3,775
  • 9
  • 39
  • 50
1

var arr = [];
var rows = 3;
var columns = 2;

for (var i = 0; i < rows; i++) {
    arr.push([]); // creates arrays in arr
}
console.log('elements of arr are arrays:');
console.log(arr);

for (var i = 0; i < rows; i++) {
    for (var j = 0; j < columns; j++) {
        arr[i][j] = null; // empty 2D array: it doesn't make much sense to do this
    }
}
console.log();
console.log('empty 2D array:');
console.log(arr);

for (var i = 0; i < rows; i++) {
    for (var j = 0; j < columns; j++) {
        arr[i][j] = columns * i + j + 1;
    }
}
console.log();
console.log('2D array filled with values:');
console.log(arr);
1

The most simple way to create an empty matrix is just define it as an empty array:

// Empty data structure
const matrix = []

However, we want to represent something similar to a grid with n and m parameters know ahead then we can use this instead.

// n x m data structure
const createGrid = (n, m) => [...Array(n)].map(() => [...Array(m)].fill(0))
const grid = createGrid(3, 5)

Here is a simple snippet showing how to use them.

const createGrid = (n, m) => [...Array(n)].map(() => [...Array(m)].fill(0))

const toString = m => JSON.stringify(m)
  .replace(/(\[\[)(.*)(]])/g, '[\n  [$2]\n]')
  .replace(/],/g, '],\n  ')

// Empty data structure
const matrix = []
console.log(toString(matrix))

matrix.push([1,2,3])
matrix.push([4,5,6])
matrix.push([7,8,9])
console.log(toString(matrix))

// n x m data structure
const grid = createGrid(3, 5)
console.log(toString(grid))
Teocci
  • 7,189
  • 1
  • 50
  • 48
0

If we don’t use ES2015 and don’t have fill(), just use .apply()

See https://stackoverflow.com/a/47041157/1851492

let Array2D = (r, c, fill) => Array.apply(null, new Array(r))
  .map(function() {
    return Array.apply(null, new Array(c))
      .map(function() {return fill})
  })

console.log(JSON.stringify(Array2D(3,4,0)));
console.log(JSON.stringify(Array2D(4,5,1)));
VLAZ
  • 26,331
  • 9
  • 49
  • 67
allenyllee
  • 964
  • 1
  • 13
  • 16
0

No need to do so much of trouble! Its simple

This will create 2 * 3 matrix of string.

var array=[];
var x = 2, y = 3;
var s = 'abcdefg';

for(var i = 0; i<x; i++){
    array[i]=new Array();
      for(var j = 0; j<y; j++){
         array[i].push(s.charAt(counter++));
        }
    }
-2

We usually know the number of columns but maybe not rows (records). Here is an example of my solution making use of much of the above here. (For those here more experienced in JS than me - pretty much everone - any code improvement suggestions welcome)

     var a_cols = [null,null,null,null,null,null,null,null,null];
     var a_rxc  = [[a_cols]];

     // just checking  var arr =  a_rxc.length ; //Array.isArray(a_rxc);
     // alert ("a_rxc length=" + arr) ; Returned 1 
     /* Quick test of array to check can assign new rows to a_rxc. 
        i can be treated as the rows dimension and  j the columns*/
       for (i=0; i<3; i++) {
          for (j=0; j<9; j++) {
            a_rxc[i][j] = i*j;
            alert ("i=" + i + "j=" + j + "  "  + a_rxc[i][j] );
           }
          if (i+1<3) { a_rxc[i+1] = [[a_cols]]; }
        }

And if passing this array to the sever the ajax that works for me is

 $.post("../ajax/myservercode.php",
       {
        jqArrArg1 : a_onedimarray,
        jqArrArg2 : a_rxc
       },
       function(){  },"text" )
        .done(function(srvresp,status) { $("#id_PageContainer").html(srvresp);} ) 
        .fail(function(jqXHR,status) { alert("jqXHR AJAX error " + jqXHR + ">>" + status );} );
GMC
  • 1
  • 1
-2

What's wrong with

var arr2 = new Array(10,20);
    arr2[0,0] = 5;
    arr2[0,1] = 2
    console.log("sum is   " + (arr2[0,0] +  arr2[0,1]))

should read out "sum is 7"

MadHaka
  • 21
  • 1
  • 4
    Now set `arr2[1,0]=4`. `console.log("sum is " + (arr2[0,0] + arr2[0,1]))` then gives "sum is 6". You did not really create a two-dimensional array, but a simple array containing the entries "10" and "20". when you try to access entries using comma-separated indizes, what you really do is described here:https://stackoverflow.com/questions/7421013/why-does-5-6-8-71-2-8-in-javascript – Daniel Nov 10 '17 at 14:57
  • What's wrong is everything about this code. `new Array(10,20)` : 1. you should avoid using the array constructor. 2. Even with the code as-is, this is a 1D array, not a 2D array. The next two lines are also wrong `arr[x,y]` is not fetching `x` and `y` coordinates in the array but [the comma operator](https://stackoverflow.com/questions/3561043/what-does-the-comma-operator-do-in-javascript) which resolves as the last expression. Thus `arr[x,y]` is ***always*** the same as `arr[y]` for assignment and retrieval. Ditto for the log. Literally every line is wrong. And the whole approach. – VLAZ Nov 09 '22 at 13:29
-2
const dp=new Array(3).fill(new Array(3).fill(-1))

It will create below array:

[ [ -1, -1, -1 ], [ -1, -1, -1 ], [ -1, -1, -1 ] ]
lemon
  • 14,875
  • 6
  • 18
  • 38
  • https://stackoverflow.com/help/how-to-answer#:~:text=Write%20to%20the%20best%20of,your%20answer%20to%20improve%20it. – levininja Dec 14 '22 at 22:31
-3

You can nest a new array as you fill the first one:

let ROWS = 2,
    COLS = 6;
let arr = new Array(ROWS).fill(new Array(COLS).fill(-1));
Output:
arr = 
[
  [-1, -1, -1, -1, -1, -1],
  [-1, -1, -1, -1, -1, -1]
]

If you're confused, lets break this down with declaring/filling 1 array: Make a new array size d, filled with any initial value

let arr1d = new Array(d).fill(<whatever_fill_val>);

Now, instead of filling your first array with a int/string/etc, you can fill it with ANOTHER array, as you fill the nested one!

let arr = new Array(d).fill(new Array(n).fill(-1));

  • https://stackoverflow.com/questions/18163234/declare-an-empty-two-dimensional-array-in-javascript#comment95492731_52268285 – CPAR Jul 18 '21 at 16:22
  • 2
    As @MrMartiniMo pointed out in a similar answer: The problem with this solution is that each row contains the same array. If you set `arr[1][2] = 1` each row will contain `[-1, -1, 1, -1]` – Arthur Weborg Aug 09 '21 at 17:13
-6

// for 3 x 5 array

new Array(3).fill(new Array(5).fill(0))
leannez
  • 225
  • 3
  • 6
  • 8
    Does not work. Each item in the first dimension contains a reference to the same secondary array. So a[0][y] === a[1][y] === a[2][y] which guaranties you some weird results. – Franck Jeannin Aug 30 '19 at 16:51