creating multi-dim arrays (JS) - javascript

I was trying to create a 3-dimensional array and couldn't find an easy way to do it.
array = [[[]]];
or
array = [][][];
or
array = []; array[] = []; array[][] = [];
would for example not work. (the console'd say the second array is 'undefined' and not an object, or for the second and third example give a parse error).
I cannot hard-code the information either, as I have no idea what the indexes and contents of the array are going to be (they are created 'on the fly' and depending on the input of a user. eg the first array might have the index 4192). I may have to create every array before assigning them, but it would be so much easier and faster if there's an easier way to define 3-dimensional arrays. (there'll be about 2 arrays, 25 subarrays and 800 subsubarrays total) every millisecond saves a life, so to say.
help please?

JavaScript is dynamically typed. Just store arrays in an array.
function loadRow() {
return [1, 2, 3];
}
var array = [];
array.push(loadRow());
array.push(loadRow());
console.log(array[1][2]); // prints 3

Since arrays in javascript aren't true arrays, there isn't really a multidimensional array. In javascript, you just have an arrays within an array. You can define the array statically like this:
var a = [
[1,2,3],
[4,5,6],
[7,8,9]
];
Or dynamically like this:
var d = [];
var d_length = 10;
for (var i = 0;i<d_length;i++) {
d[i] = [];
}
UPDATE
You could also use some helper functions:
function ensureDimensions(arr,i,j,k) {
if(!arr[i]) {
arr[i] = [];
}
if(!arr[i][j]) {
arr[i][j] = [];
}
}
function getValue(arr,i,j,k) {
ensureDimensions(i,j,k);
return arr[i][j][k];
}
function setValue(arr,newVal,i,j,k) {
ensureDimensions(i,j,k);
arr[i][j][k] = newVal;
}

Related

Reverse() doesn't work in array with string key

Why reverse() doesn't work if my array have elements with string as a key.
var myArray = [];
myArray["test"] = 100;
myArray["test2"] = 200;
console.log(myArray)
console.log(myArray.reverse())
Both returns the same result.
How can I change it to make it work?
DEMO: https://www.w3schools.com/code/tryit.asp?filename=GG4PXCHZ4VUD
.reverse() is a function of arrays, where elements are indexed by their position. Your code is not adding elements to the array, but rather adding properties on the array object. This works and the properties can be accessed, but reversing does nothing as these are not elements. The array is still of 0 length.
You will have to either:
Make myArray an object of a different type. In this case, reverse will still not work, and you will have to write code to sort manually. Other answers have provided some guidance as to how to achieve this
Add your elements to the array using push() or numeric indices, in which case you'll lose the string indices but can use array sorting methods such as .reverse()
While numbers have an intrinsic ordering, object property keys follow different rules. If you want to reverse a string-indexed object, consider writing a function to insert objects to a new Map in reverse order.
Arrays values are only accessible by index.
myArray[0] = 100;
myArray[1] = 200;
console.log(myArray) // [100, 200]
console.log(myArray.reverse()) // [200, 100]
You can store values by keys in objects.
var myObject = {};
myObject["test"] = 100;
myObject["test2"] = 200;
console.log(myObject) // {test: 100, test2: 200}
That said, you can reverse an object by doing this:
Object.entries(myObject).reverse().reduce((a, b) => {
a[b[0]] = b[1];
return a
},{})
Since you do not actually need any array methods, it would be better to simply use an object instead.
You can create a new reversed array by looping over Object.keys() backwards. See the code in action here.
var myArray = [];
myArray["test"] = 100;
myArray["test2"] = 200;
function reverseAssociative(arr){
const keys = Object.keys(arr);
const res = [];
for(let i = keys.length - 1; i >= 0; i--){
res[keys[i]] = arr[keys[i]];
}
return res;
}
const res = reverseAssociative(myArray);
for(const key in res){
console.log(key, res[key]);
}
You can simplify it by using reduce on Object.entries after reversing. See the code in action here.
myArray = Object.entries(myArray).reverse().reduce((acc,[key,val])=>(acc[key]=val,acc),[])

JavaScript : Pass-by-reference issues when creating an unknown dimension multi dimensional array function

I'm posting this question because I am trying to make a function that allows someone to create a multi-dim array. So, the user inputs an array of numbers which are the dimensions of the array (e.g entering [2, 4, 3] would output a 2x4x3 multi-dim array)
I have spent a couple of hours trying to imagine an algorithm that can do this in JS and I came up with this:
Note: I use Node.js v9.11.1
function generate(dimensions) {
// SA = sub-array (I will use this several times here)
// This array will store every SAs of the multi-dim array
// E.g for a 2x4x3 array, it will store a 2-item array, a 4-item array and a 3-item array
var arrays = []
// This fills `arrays` with the SAs
for (var i = 0; i < dimensions.length; i++) arrays.push(new Array(dimensions[i]).slice(0))
// Here it gets a bit complex (at least for me!)
// So what we do is that for each SA (except last), we fill it with copies of the current+1 SA
// So the SA at index 1 will be filled with copies of the array at index 2
// And the array at index 0 will be filled with arrays of index 1 (which was already filled because our for loop starts from the end)
// The array at index 0 is our final multi-dim array
// Goes from the before last SA to the first
for (var current = dimensions.length-2; current !== -1; current--) {
// Fills the current SA with index+1 SA
for (var i = 0; i < arrays[current].length; i++) arrays[current][i] = arrays[current+1].slice(0)
}
// Returns first array, the complete one
return arrays[0].slice(0)
}
My problem is that even if the array is well generated, some SA are passed by reference and not by value so when I do
my_array = generate([2, 4, 3])
my_array[1][2][1] = "hi!" // Fill a random place with "hi!"
Then when I do console.log(my_array), some other cases of the multi-dim array are filled with the same value.
This means that somewhere, an array is passed by reference rather than passed by value which is strange
because I checked the code multiple times and I don't find where this could come from (I use the Array.slice()
method to "copy" the array)
Have I missed something huge?
Your help would be rather appreciated!
To be honest, not sure how your trying to create your mult-dim array,..
But the first thing that springs to mind when seeing something like this, is recursion.
eg..
function generate(dimensions) {
if (!dimensions.length) throw new Error("no dims?");
const dimsize = dimensions[0];
if (dimensions.length === 1) {
return new Array(dimsize).fill(null);
}
const ret = [];
const subdims = dimensions.slice(1);
for (let l = 0; l < dimsize; l+= 1)
ret.push(generate(subdims));
return ret;
}
const my_array = generate([2, 4, 3])
my_array[1][2][1] = "hi!"
console.log(my_array);
I come up with this:
function generate(dims) {
if(dims.length > 0) {
let array = new Array(dims[0]).fill(0);
let childDims = dims.slice();
childDims.shift();
return array.map((el) => {
return generate(childDims);
});
} else return 0;
}
let foo = generate([2, 3, 2]);
foo[0][0][1] = 'hmmmm';
console.log(foo);
Also using recursion to create multidimensional array. But when creating arrays as You saw, have to be carefull about not passing references but real copies of arrays. Slice() will give You only shallow copy.

Giving an array of indexes, how to push items from one array to another depending on the indexes that are specified?

I am trying to push items from one Array to another depending on the order that is supplied. Essentially i have a 2d array with a name and a price :
var myArray = [['Apples',22],['Orange',55],['Berry',23]];
Another array with the order it should be in :
var myOrder = [0,2,1];
My resulting array would look like this :
var finalArray = [['Apples',22],['Berry',23],['Orange',55]]
My initial thought process was to loop through myArray and loop through myOrder , store the object temporary at a specified index in myOrder then push to final array. I think i am over thinking it a bit, i made several attempts but with no luck whatsoever. Any help would be greatly appreciated!
This is a simple map() that doesn't require anything else
var myArray = [['Apples',22],['Orange',55],['Berry',23]];
var myOrder = [0,2,1];
let final = myOrder.map(i => myArray[i])
console.log(final)
The optimal way appears to me to be:
Initialize empty finalArray
Loop over your myOrder array
2.1. Push myArray[index] to finalArray
Like so:
let finalArray = [];
for(let index of myOrder) {
finalArray.push(myArray[index]);
}
Review the for...of syntax if you're not familiar with it.
You can use splice to insert so long as the same number of elements are present in both the arrays.
You iterate over the myOrder array and then use splice, to which the index of the new array is the current value of the iteration and then use array present in the index position of myArray
var myArray = [['Apples',22],['Orange',55],['Berry',23]];
var myOrder = [0,2,1];
var finalArray = [];
myOrder.forEach(function(val, index) {
finalArray.splice(val, 0, myArray[index]);
});
console.log(finalArray);
Easy enough using .reduce:
var myArray = [['Apples',22],['Orange',55],['Berry',23]];
var myOrder = [0,2,1];
function reorder(array, order) {
return order.reduce((newArray, orderIndex) => {
newArray.push(array[orderIndex]);
return newArray;
}, []);
}
console.log(reorder(myArray, myOrder))
function reorder(arr, order) {
return order.map(function(i) {
return arr[i];
});
}
var myArray = [['Apples',22],['Orange',55],['Berry',23]];
var myOrder = [0,2,1];
reorder(myArray, myOrder); // => [["Apples",22],["Berry",23],["Orange",55]]
One of way solving this will be
var myArray = [['Apples',22],['Orange',55],['Berry',23]];
var myOrder = [0,2,1];
var finalArray;
for (x in myOrder) {
finalArray[x] = myArray[myOrder[x]];
}
This is a beginning level solution. Also you use libraries available for java script such as underscore.js(http://underscorejs.org/) for such operations on Array and Object.
Also you can use ECMA 6, for doing this which will reduce your line of coding.
Example-
var myArray = [['Apples',22],['Orange',55],['Berry',23]];
var myOrder = [0,2,1];
let finalArray = myOrder.map(i => myArray[i])
This is the new way of coding in javascript.
In my point of view, it will be easy if you learn latest version of Java script(ECMAscript 6)

When to use object and when array

I have an situation where I have 3 different arrays with very different amounts of objects in it. I've read many questions and blog posts about this but Im still unsure when to use what.
PS! My biggest problem is that I need to iterate and push (perfect for arrays), also find if exists in array and delete (more suitable for objects). Specific order is not required.
I can't allow having same object in both array1 and array1clicked
because they should perform different actions.
When it's best to use object and when array in my example? What should I replace with object and what should stay as array? Im pretty sure that amounts of objects in it also matters, right?
My current code:
//Objects in arrays are literally custom {objects} with custom prototypes and html
var array1 = [ 20 objects ];
var array1clicked = [];
var array2 = [ 250 objects ];
var array2clicked = [];
var array3 = [ 50 000 objects ];
var array3clicked = [];
//Each object in arrays has event attached
objecthtml.click(function() {
//Add to clicked array
array1clicked.push(thisobject);
//Remove from initial array
var index = array1.indexOf(thisobject);
if (index > -1) {
array1.splice(index, 1);
}
}
//Same with array2 and array3 objects
//Iterations on different conditions
var array1count = array1.length;
var array1clickedcount = array1clicked.length;
//Same with array2 and array3
if(condition1) {
for(a = 0; a < array1count; a++) {
array1[a].div.style.visibility = 'hidden';
}
//Same with array2 and array3 objects
for(a = 0; a < array1clickedcount; a++) {
array1clicked[a].div.style.visibility = 'visible';
}
//Same with array2clicked and array3clicked objects
}
else if(condition2) {
for(a = 0; a < array1count; a++) {
array1[a].div.style.visibility = 'visible';
}
//Same with array2 and array3 objects
for(a = 0; a < array1clickedcount; a++) {
array1clicked[a].div.style.visibility = 'hidden';
}
//Same with array2clicked and array3clicked objects
}
It seems you want a data structure with these operations:
Iteration
Insert
Delete
Search
With arrays, the problem is that searches and deletions (with reindexing) are slow.
With objects, the problem is that the property names can only be strings.
The perfect structure is a set.
var s = new Set();
s.add(123); // insert
s.has(123); // search
s.delete(123); // delete
s.values(); // iterator
In your case, I think you have to use just Array.
In common case, you could use object to keep references and push some values into it, but If you wanna iterate on this, I think you have to use Array.

How to create empty 2d array in javascript?

How do I create an empty 2D array in Javascript (without knowing how many rows or columns there will be in the new array)?
If it's a simple array var newArray = new Array(); I can assign as many elements as I want. But what about a 2D array? Can I create one without specifying the numbers of rows and columns? and how do I access the elements afterwards (myArray[0][1] or myArray[0,1])?
You can create a 6 x 6 empty array like this:
var myGrid = [...Array(6)].map(e => Array(6));
Array(6) generates an array with length = 6 and full of undefined values.
We map that array to another array full of undefined values.
In the end, we get a 6x6 grid full of undefined positions.
If you need to initialize the grid with a default value:
var value = 'foo'; // by default
var myGrid = [...Array(6)].map(e => Array(6).fill(value));
Now you have a 6 x 6 grid full of 'foo'.
Yes you can create an empty array and then push data into it. There is no need to define the length first in JavaScript. Check out jsFiddle Live Demo
Define:
const arr = [[],[]];
Push data:
arr[0][2] = 'Hi Mr.A';
arr[1][3] = 'Hi Mr.B';
Read data:
alert(arr[0][2]);
alert(arr[1][3]);
Update:
Here is also a video recommended by Brady Dowling:
Create a 2D array: ([https://www.youtube.com/watch?v=tMeDkp1J2OM][2])
There are no two dimensional arrays in Javascript.
To accomplish the effect of a two dimensional array, you use an array of arrays, also known as a jagged array (because the inner arrays can have different length).
An empty jagged array is created just like any other empty array:
var myArray = new Array();
You can also use an empty array literal:
var myArray = [];
To put any items in the jagged array, you first have to put inner arrays in it, for example like this:
myArray.push([]);
myArray[0][0] = 'hello';
You can also create an array that contains a number of empty arrays from start:
var myArray = [[],[],[]];
That gives you a jagged array without any items, but which is prepared with three inner arrays.
As it's an array of arrays, you access the items using myArray[0][1].
Say you wanted to make a 2d array (i.e. matrix) that's 100x100, you can do it in one line, like this:
var 2darray = new Array(100).fill(null).map(()=>new Array(100).fill(null));
This will create a 100x100 matrix of NULL's.
Replace the 100x100 with whatever dimensions you want, and the null's with whatever is your prefered default value, or blank for undefined.
You can use a simple for loop to create an array of the approximate size and then push more rows if need be.
const arr = [];
const n = 7;
const m = 5;
for (let i = 0; i < n; i++) {
arr.push(new Array(m).fill(0));
}
const arr = [];
const n = 7;
const m = 5;
for (let i = 0; i < n; i++) {
arr.push(new Array(m).fill(0));
}
console.log(arr);
var myArray = [
["cats","dogs","monkeys","horses"],
["apples","oranges","pears","bananas"]
];
document.write(myArray[0][2]) //returns "monkeys"
Two things:
1) The array length property improperly reports the array length if called after the var myArray = [[],[]]; statement. Technically, since the empty arrays are defined, they are getting counted by the length property, but in the spirit of the length property it really should return 0, because no non-empty elements have been added to any of the arrays.
A minimum work around is to use two nested for( in ) loops, one for the 1st array and one for the 2nd array, and to count the non-undefined elements.
2) Extending Siamak A.Motlagh example and adding a arr([2][4]) = 'Hi Mr.C'; assignment fails with an "Uncaught TypeError: Cannot set property '4' of undefined" error.
See the jsFiddle: http://jsfiddle.net/howardb1/zq8oL2ds/
Here is a copy of that code:
var arr = [[],[]];
alert( arr.length ); // wrong!
var c = 0;
for( var i in arr )
for( var j in arr[ i ] )
if( arr[ i ][ j ] != undefined )
++c;
alert( c ); // correct
arr[0][2] = 'Hi Mr.A';
alert(arr[0][2]);
arr[1][3] = 'Hi Mr.B';
alert(arr[1][3]);
arr[2][4] = 'Hi Mr.C'; // At this point I'm getting VM558:62 Uncaught TypeError: Cannot set property '4' of undefined
alert(arr[2][4]);
var c = 0;
for( var i in arr )
for( var j in arr[ i ] )
if( arr[ i ][ j ] != undefined )
++c;
alert( c );
Why does the third assignment fail? What about the [[],[]] creation statement told it that the first array was valid for 0 and 1, but not 2 or that 2 and 3 were ok for the second array, but not 4?
Most importantly, how would I define an Array in an Array that could hold date objects in the first and second arrays. I'm using the jQuery-UI DatePicker, which expects an array of dates, as in date objects, which I've extended to use a second date array to contain date objects that contain times so I can keep track of multiple dates, and multiple times per day.
Thanks.
The functions I use
function get_empty_2d_array(numRows, numColumnns) {
return [...Array(numRows)].map(e => Array(numColumnns));
}
function get_2d_array_filled(numRows, numColumnns, fillValue) {
return [...Array(numRows)].map(e => Array(numColumnns).fill(fillValue));
}
This also works as an expression:
var twoDarr= new Array(desiredLength);
for (i=0;i<twoDarr.length;i++) {twoDarr[i]=[];}
I don't know how it pars in terms of performance with the rest of the answers here, if you have a clue let me know in the comments.
If you don't know the length of the array beforehand pls have in mind that you can use either push([]), or splice() if you want to push/remove/replace a new element in place of an existing one.
const grid = new Array(n).fill(new Array(n))

Categories