0

How would I go about calculating the average of all the values in a multidimensional array? I've written a function to calculate the average from a 1-dimensional array, but I'm not sure what the best method is when there are more than 1-dimensions.

For example, let's say we have the following:

var A = Array(3);
for (i=0; i<A.length; i++) {
    A[i] = new Array(2);
    for (j=0; j<A[i].length; j++) {
        A[i][j] = i+j;
    }
}

Therefore, A is a 2-dimensional array, or 3x2 matrix:

A = 0   1
    1   2
    2   3

So I'd like to find the average of all the values, which in this case would equal 1.5. I imagine I need to create a new 1-dimensional array of all the values, which I could then feed into my averaging function. However, I'm not sure of the easiest way to do this when the array is highly-dimensional (e.g. 5x3x6x9).

Thanks!

EDIT

Thanks everyone! I've used your advice and flattened the array using code I found in one of the attached links which uses the reduce function. My averaging function is now like this:

function average(x) {

    // Flatten multi-dimensional array
    while (x[0] instanceof Array) {
        x = x.reduce( function(a, b) { return a.concat(b); } );
    }

    // Calculate average
    return x.reduce( function(a, b) { return a + b; } )/x.length;
}
1
  • You have to define the expected logic. How would you implement this feature in a mathematical assignment? Commented Nov 3, 2011 at 17:00

4 Answers 4

1

You can use this code to flatten the multi-dimensional array:

function flatten(array){
    var flat = [];
    for (var i = 0, l = array.length; i < l; i++){
        var type = Object.prototype.toString.call(array[i]).split(' ').pop().split(']').shift().toLowerCase();
        if (type) { flat = flat.concat(/^(array|collection|arguments|object)$/.test(type) ? flatten(array[i]) : array[i]); }
    }
    return flat;
}

and then just sum and divide:

var total = 0;
for (var i = 0, l = flattenedArray.length; i<l; i++) {
  total += flattenedArray[i];
}
var average = total/flattenedArray.length;
Sign up to request clarification or add additional context in comments.

2 Comments

External links are a great adjunct to an answer, but always copy the relevant code into the answer as well. External resources can move, get deleted, get modified in a way that makes them irrelevant, etc. Stack Overflow is meant not just for answering the OP's question right now, but for others with the same sort of question in the future.
Okay @T.J.Crowder, will do :)
1

I don't see any particular reason you need to create a new array. Just loop through the ones you have:

var i, j, sub, total, count, avg;

total = count = 0;
for (i = 0; i < A.length; ++i) {
    sub = A[i];
    count += sub.length;
    for (j = 0; j < sub.length; ++j) {
        total += sub[j];
    }
}
avg = count === 0 ? NaN : total / count;

Note that the above assumes the arrays are not sparse (they aren't in your example).

Comments

1

// The simplest method is to flatten the array

Array.prototype.flatten= function(){
var A= [];
this.forEach(function(itm){
    if(!itm || !itm.flatten)A.push(itm);
    else{
        A= A.concat(itm.flatten());
    }
});
return A;
}
// shim for older browsers (without array forEach)
Array.prototype.forEach= [].forEach || function(fun, scope){
    var T= this, L= T.length, i= 0;
    if(typeof fun== 'function'){
        while(i< L){
            if(i in T){
                fun.call(scope, T[i], i, T);
            }
            ++i;
        }
    }
    return T;
}

var a=[[1,2,3,[1,2,3]],[4,5,6,[7,8,[1,2,3,[1,2]]]],11,[1,[2,[2,4,[5]]]]];
a.flatten().join('\n')

/*  returned value: (String)
1
2
3
1
2
3
4
5
6
7
8
1
2
3
1
2
11
1
2
2
4
5
*/

Comments

1

You can flatten your multidimensional-array with this function:

function flatten(arr) {
    var acc = [];
    var f = function(arr) {
        for (var i = 0; i < arr.length; ++i) {
            if (arr[i] instanceof Array) {
                f(arr[i]);
            }
            else {
                acc.push(arr[i]);
            }
        }
    };
    f(arr);
    return acc;
}

And then you can calculate the average with your function.

3 Comments

x instanceof Array is not reliable in an environment where multiple windows (such as iframes) may be used. The most reliable way to find out whether you're really dealing with an array is Object.prototype.toString.call(x) === "[object Array]".
@T.J.Crowder: good advice if multiple windows are used. Thanks!
You can also use Array.isArray(). Although I'm not sure about browser support

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.