Monday, June 3, 2024
 Popular · Latest · Hot · Upcoming
129
rated 0 times [  130] [ 1]  / answers: 1 / hits: 23069  / 8 Years ago, thu, october 6, 2016, 12:00:00

I have an example of nested array:



var testArray = [1,2,[3,4,[5,6],7],8,9,[10,11],12];


Here is my function for getting nested array length:



Array.prototype.getLength = function() {
var sum = 0;
function getMultiLength(array) {
for (count = 0; count < array.length; count ++) {
sum ++;
if (!array[count].length) {
getMultiLength(array[count]);
}
}
}
getMultiLength(this.valueOf());
return sum;
};


My expectation for result would be 12, but instead what I got is infinite loop:



testArray.getLength(); //infinite loop


Anyone know why and how to get nested array length?


More From » arrays

 Answers
21

Problem with your code



Your existing code fails because the check for recursing is backward. You want to recurse if the length is non-zero. So it should be



  if (array[count].length) getMultiLength(array[count]);
else sum++;


As your code stands, getMultiLength will be called even if array[count] is not an array (because if array[count] is not an array, length will be undefined). So it will keep recursing forever. This would be pretty easy to figure out by just stepping through your code in the debugger.



By the way, you don't need this.valueOf(). That is the same as this in this case.



Tweaking your code



But actually, you could streamline your code by eliminating the unnecessary inner function, and using the return value of the recursive calls:



Array.prototype.getLength = function() {
let sum = 0;
for (let count = 0; count < this.length; count ++) {
sum += this[count].length ? this[count].getLength() : 1;
}
return sum;
};


Some people might prefer to write this using reduce:



Array.prototype.getLength = function() {
return this.reduce((sum, elt) =>
sum + (elt.length ? elt.getLength() : 1), 0);
};


Another solution using flattening



An alternative solution is to flatten the array, then find the length of the flattened array. Here we use a generator to create a flattener which is real easy to read and understand (ES6 feature):





function *flatten(array) {
for (elt of array)
if (Array.isArray(elt)) yield *flatten(elt);
else yield elt;
}

var testArray = [1,2,[3,4,[5,6],7],8,9,[10,11],12];

console.log(Array.from(flatten(testArray)).length);





Alternative implementation of flatten



Or, use your own favorite implementation of flatten, such as this recursive version:



function flatten(value) {
return Array.isArray(value) ? [].concat(...value.map(flatten)) ? value;
}


or in ES5



function flatten(value) {
return Object.prototype.toString.call(value) === '[object Array]' ?
[].concat.apply([], value.map(flatten)) :
value;
}


Putting it on the Array prototype



If you insist on putting this on the prototype, then



Object.defineProperty(Array.prototype, 'getLength', {
value() { return flatten(this).length; }
});


Use defineProperty to make this property non-enumerable, non-configurable etc.


[#60486] Tuesday, October 4, 2016, 8 Years  [reply] [flag answer]
Only authorized users can answer the question. Please sign in first, or register a free account.
lelasamiraa

Total Points: 208
Total Questions: 99
Total Answers: 107

Location: Uzbekistan
Member since Tue, Nov 30, 2021
3 Years ago
lelasamiraa questions
Thu, Jul 16, 20, 00:00, 4 Years ago
Thu, Oct 17, 19, 00:00, 5 Years ago
Mon, Aug 5, 19, 00:00, 5 Years ago
Thu, Feb 7, 19, 00:00, 5 Years ago
;