const dimensions = [ arr.length, arr[0].length ];
This works, if you know length of the inner arrays never change.
If the dimension of the inner arrays aren't static (jagged array), you could combine Array.reduce and Math.max to calculate the largest dimension:
const dimensions = [
arr.length,
arr.reduce((x, y) => Math.max(x, y.length), 0)
];
Answer from Alex on Stack Overflowconst dimensions = [ arr.length, arr[0].length ];
This works, if you know length of the inner arrays never change.
If the dimension of the inner arrays aren't static (jagged array), you could combine Array.reduce and Math.max to calculate the largest dimension:
const dimensions = [
arr.length,
arr.reduce((x, y) => Math.max(x, y.length), 0)
];
Considering that sub lists can have different size, get the minimum size or depending on need make it max
function size(ar){
var row_count = ar.length;
var row_sizes = []
for(var i=0;i<row_count;i++){
row_sizes.push(ar[i].length)
}
return [row_count, Math.min.apply(null, row_sizes)]
}
size([[1, 1, 1], [1, 1, 1]])
Output:
[2, 3]
An array is a sorted set of numeric key value pairs. "_u" + user_id is not numeric, it's a string, therefore it gets stored as a regular property on the array (it behaves like an object) and not as part of the array itself. If you want to use a key-value storage with a length, use a Map.
const test = { // no need for a class if you dont have instances
arr: new Map(), // no need for that unneccessary init
add() {
let user_id = Math.floor(Math.random() * 10000);
if(!this.arr.has("u_" + user_id)) { // I prefer "this" over "test", both work however
this.arr.set("u_" + user_id, []);
}
this.arr.get("u_" + user_id).push({"somedata": "here"});
},
length() {
return this.arr.size; //Note: it is "size" not "length" on a Map
},
};
Sidenote: arr and test are very bad names.
An array index can be defined as number only. If you want to get the length of an array, there are two ways to achieve this.
- You need to define the index as number instead of a string.
Make a separate object, add your object (
{"somedata": "here"}) into the object and push it into the array. Check the code below.let test=[] let obj = {} let user_id = Math.floor(Math.random() * 10000); if(obj["u_" + user_id] === undefined) { obj["u_" + user_id] = []; } obj["u_" + user_id] = {"somedata": "here"}; test.push(obj)
Hope this will be helpful.
There's no shortcut, you have to sum up the lengths of the arrays. If you only have two dimensions, then:
var matrix = [1,2,3,4,5,6, [1,2,3,4]];
var sum = matrix.reduce(function(acc, entry) {
return acc + (Array.isArray(entry) ? entry.length : 1);
}, 0);
console.log(sum);
If you may have more dimensions, you'll need recursion. As squint pointed out in a comment, making the above recursive is just a matter of giving our reduce callback a name and then doing reduce again instead of just using array.length:
var matrix = [1,2,3,4,5,6, [1,2,[3,4]]];
var sum = matrix.reduce(function callback(acc, entry) {
return acc + (Array.isArray(entry) ? entry.reduce(callback, 0) : 1);
}, 0);
console.log(sum);
Some notes:
Array.isArrayandArray#reducewere added in ES5 (in 2009) and so should be available in just about any modern browser (so, not IE8); they can both be shimmed/polyfilled on older browsers.- JavaScript doesn't actually have multi-dimensional arrays. It has arrays of arrays.
- The recursive example above uses a construct called a named function expression for
callback. NFEs have a bad name because years ago browsers got them wrong several different ways, but these days they're fine. (If you used the above on IE8 — including polyfills for the things it's missing — even it would work even though IE8 gets NFEs wrong.)
Building on @T.J. Crowder's solution with reduce, I would suggest to turn things around a bit so there is only one mention of reduce in the code. And to spice it up, this is with arrow syntax:
function entries(a) {
return Array.isArray(a) ? a.reduce((acc, el) => acc + entries(el), 0) : 1;
}
var matrix = [1,2,3,4,5,6, [1,2, [3,4]]];
console.log(entries(matrix));
This way it will even work for non-array arguments: return value is 1 in that case. Obviously not that important.
This recursive function returns all dimensions of a given array or false if one or more dimensions are not straight (i.e. different sizes between array items). It uses a helper function to determine whether two simple arrays are the same (read the function comments before using it).
// pre: a !== b, each item is a scalar
function array_equals(a, b)
{
return a.length === b.length && a.every(function(value, index) {
return value === b[index];
});
};
function getdim(arr)
{
if (/*!(arr instanceof Array) || */!arr.length) {
return []; // current array has no dimension
}
var dim = arr.reduce(function(result, current) {
// check each element of arr against the first element
// to make sure it has the same dimensions
return array_equals(result, getdim(current)) ? result : false;
}, getdim(arr[0]));
// dim is either false or an array
return dim && [arr.length].concat(dim);
}
console.log(getdim(123)); // []
console.log(getdim([1])); // [1]
console.log(getdim([1, 2])); // [2]
console.log(getdim([1, [2]])); // false
console.log(getdim([[1, 2], [3]])); // false
console.log(getdim([[1, 2],[1, 2]])); // [2, 2]
console.log(getdim([[1, 2],[1, 2],[1, 2]])); // [3, 2]
console.log(getdim([[[1, 2, 3],[1, 2, 4]],[[2, 1, 3],[4, 4, 6]]])); // [2, 2, 3]
console.log(getdim([[[1, 2, 3], [1, 2, 4]], [[2, 1], [4, 4]]])); // false
Run code snippetEdit code snippet Hide Results Copy to answer Expand
Here is a simple recursive function to do that. Wrote it very quickly, so may prone to errors.
This function returns the lengths of each dimensions. If it contains sub-arrays of different lengths, this function returns false.
This function works for different dimensions.
For example, passing a 2d array of 2x3 will return [2, 3], a 3d array of 2x3x4 will return [2, 3, 4]. The dimension (i.e. n d) can be obtained by checking the length of the returned array.
// Array dimension checker
// Returns:
// false when array dimensions are different
// an Array when is rectangular 0d (i.e. an object) or >=1d
function arrayDimension(a) {
// Make sure it is an array
if (a instanceof Array) {
// First element is an array
var sublength = arrayDimension(a[0]);
if (sublength === false) {
// Dimension is different
return false;
} else {
// Compare every element to make sure they are of the same dimensions
for (var i = 1; i < a.length; i++) {
var _sublength = arrayDimension(a[i]);
// HACK: compare arrays...
if (_sublength === false || sublength.join(",") != _sublength.join(",")) {
// If the dimension is different (i.e. not rectangular)
return false;
}
}
// OK now it is "rectangular" (could you call 3d "rectangular"?)
return [a.length].concat(sublength);
}
} else {
// Not an array
return [];
}
}
Demo (Check the javaScript console :) )
Those are not arrays. They're objects, or at least they're being treated like objects. Even if they are Array instances, in other words, the "length" only tracks the largest numeric-indexed property.
JavaScript doesn't really have an "associative array" type.
You can count the number of properties in an object instance with something like this:
function numProps(obj) {
var c = 0;
for (var key in obj) {
if (obj.hasOwnProperty(key)) ++c;
}
return c;
}
Things get somewhat messy when you've got inheritance chains etc, and you have to work out what you want the semantics of that to be based on your own architecture.
.length only works on arrays. It does not work on associative arrays / objects.
patientsData["XXXXX"] is not an array. It's a object. Here's a simple example of your problem:
var data = {firstName: 'a name'};
alert(data.length); //undefined
Object.keys(Accounts).length
You are trying to get the "length" of an object, which does not exist. If this were an array, it would be enclosed in a bracket [].
This is definitely an object, so in order to count the properties inside an object, you would have to use Object.keys() to contain the property names in an array and then count the elements from there.
You can use a for loop to iterate over all the elements in the object and a count to get the number:
var Accounts = {
'Account001' : { 'data1' : 'foo1', 'data2' : 'bar1' },
'Account002' : { 'data1' : 'foo2', 'data2' : 'bar2' },
'Account003' : { 'data1' : 'foo3', 'data2' : 'bar3' },
'Account004' : { 'data1' : 'foo4', 'data2' : 'bar4' }
};
var count = 0;
for(var k in Accounts) {
if(Accounts.hasOwnProperty(k)) {
count++;
}
}
console.log(count);
You could reduce and recurse while keeping track of arrays that have been seen:
var depthCount = function(xss, depth) {
depth = depth || 0
var seen = []
return xss.reduce(function(acc, xs) {
if (Array.isArray(xs)) {
return acc.concat(depthCount(xs, depth + 1))
}
if (seen.indexOf(xss) < 0) {
seen.push(xss)
return acc.concat({depth: depth, count: xss.length})
}
return acc
}, [])
}
var xs = [1, 2, 3, 4, [5, [6], 7]]
console.log(depthCount(xs))
// [{depth: 0, count: 5},
// {depth: 1, count: 3},
// {depth: 2, count: 1}]
Then you can find out the total by filtering the collection by depth and checking the count. If you sum up the counts it will work when you have multiple arrays of the same depth too:
var xs = [1, [2, 3], [4, 5, [6, 7]]]
var count = depthCount(xs)
console.log(count)
// [{depth: 0, count: 3},
// {depth: 1, count: 2},
// {depth: 1, count: 3},
// {depth: 2, count: 2}]
var countTotalDepth = function(depth, coll) {
return coll.filter(function(obj) {
return obj.depth === depth
}).reduce(function(x, y) {
return x.count + y.count
})
}
console.log(countTotalDepth(1, count)) // 5
You can have a helper method get the count of members recursively, then use the main method to just access which layer count is wanted using "layer":
Pseudocode for helper function:
// Count members, and store if object
// Recursively get list of lengths from those objects
// Sum up those lists
// find length of longest array
// sum up all values, up to length of longest array
// Insert 'count' at front of the list
// Return
Full code:
/*
Main function
Returns a number: the count of members in a layer
*/
function getLength(layer, obj)
{
return getAllLengths(obj)[layer];
}
/*
Helper function for getLength(..)
Returns an array
*/
function getAllLengths(obj)
{
var count = 0; // for this layer's # of members
var objectMembers = []; // list of members that are objects
var objectsLists = []; // to store list of lists produced recursively from objectMembers
var result = []; // to return
// count, and store if object
for (var mem in obj)
{
count++;
if (obj[mem] instanceof Object)
{
objectMembers.push(obj[mem] );
}
}
// recursively get objects' lists
for (var i in objectMembers)
{
objectsLists.push(getAllLengths(objectMembers[i] ));
}
////// sum up lists
// find length of longest array
var maxLength = 0;
for (var i in objectsLists)
{
if (objectsLists[i].length > maxLength)
{
maxLength = objectsLists[i].length;
}
}
// sum
for (var i = 0; i < maxLength; i++)
{
var sum = 0;
for (var j = 0; j < objectsLists.length; j++)
{
if (objectsLists[j][i] != undefined)
sum += objectsLists[j][i];
}
result.push(sum);
}
// complete resulting list to return
result.splice(0,0, count);
return result;
}
Here's a quick way I've found to make a two dimensional array.
function createArray(x, y) {
return Array.apply(null, Array(x)).map(e => Array(y));
}
You can easily turn this function into an ES5 function as well.
function createArray(x, y) {
return Array.apply(null, Array(x)).map(function(e) {
return Array(y);
});
}
Why this works: the new Array(n) constructor creates an object with a prototype of Array.prototype and then assigns the object's length, resulting in an unpopulated array. Due to its lack of actual members we can't run the Array.prototype.map function on it.
However, when you provide more than one argument to the constructor, such as when you do Array(1, 2, 3, 4), the constructor will use the arguments object to instantiate and populate an Array object correctly.
For this reason, we can use Array.apply(null, Array(x)), because the apply function will spread the arguments into the constructor. For clarification, doing Array.apply(null, Array(3)) is equivalent to doing Array(null, null, null).
Now that we've created an actual populated array, all we need to do is call map and create the second layer (y).
One liner to create a m*n 2 dimensional array filled with 0.
new Array(m).fill(new Array(n).fill(0));