开发者

Aggregating object values of JavaScript arrays?

In JavaScript, given n number of arrays as input in this format: (n=2)

array1:
[{x: 1, y: 5},{x: 2, y: 3},{x: 3, y: 6}]

array2:
[{x: 1, y: 2},{x: 2, y: 6},{x: 3, y: 2}]

Ho开发者_如何学JAVAw do I aggregate the Y-values easily and get this resulting array:

arrayOutput:
[{x: 1, y: 7},{x: 2, y: 9},{x: 3, y: 8}]

Thank you.


Update: The additional comment about the x values and their positions in the arrays makes the below irrelevant.

There's no particular trick, you just loop through the arrays and build up your result. It's nothing more than a nested loop. If you're trying to be maximally efficient across a broad range of JavaScript engines, avoid unnecessary function calls.

Something along the lines of:

function sumYValues(arrays) {
    var outer, inner, array, entry, sum, result, x;

    // Create our result array with a copy of the first array
    result = [];
    if (arrays.length > 0) {
        array = arrays[0];
        for (inner = 0; inner < array.length; ++inner) {
            entry = array[inner];
            result[inner] = {x: entry.x, y: entry.y};
        }

        // Add in the remaining values
        for (outer = 1; outer < arrays.length; ++outer) {
            array = arrays[outer];
            // You might want an assert here verifying that result.length == array.length
            for (inner = 0; inner < array.length; ++inner) {
                entry = array[inner];
                // You might want an assert here verifying that result[inner].x == entry.x
                result[inner].y += entry.y;
            }
        }
    }

    return result;
}

Those loops count from 0 (or 1) to array.length - 1. You might profile whether going backwards (array.length - 1 to 0 (or 1)) is any faster, mostly the "down to 0" one. I used to assume it was because it was in C when I was a fresh-faced youth (comparisons to 0 are faster than comparisons to another variable), but that assumption may or may not be valid in JavaScript.


There's no particular shortcut, you just loop through the arrays, do your comparisons, and build up your result.

If the x values will be unique in each array, it may be easier to keep track of your ongoing sum by using an object rather than an array and using x values as keys, and then converting it into an array when you're done. E.g.:

function sumYValues(arrays) {
    var outer, inner, ar, entry, sum, result, x;

    sum = {};
    for (outer = 0; outer < arrays.length; ++outer) {
        ar = arrays[outer];
        for (inner = 0; inner < arrays.length; ++inner) {
            entry = ar[inner];
            sum[entry.x] = (sum[entry.x] || 0) + entry.y;
        }
    }

    result = [];
    for (x in sum) {
        result.push({x: x, y: sum[x]});
    }

    return result;
}

The above is mostly just to demonstrate using sum, an object, as a map of x => y values, although it does implement at least some of the summing logic as well.

This line may need some explanation:

            sum[entry.x] = (sum[entry.x] || 0) + entry.y;

If sum doesn't have an entry for that x value, sum[entry.x] will be undefined, which is a "falsey" value. So we use the curiously-powerful || operator to either get the value for that x from sum or 0, and then add the current entry's y to it and store the result.


Benchmark Example

Note that the mixed code is faster followed by loops followed by native/underscore.

function createOutput(arr1, arr2, arr3 /*, ... */) {
    return Array.prototype.reduce.call(arguments, function (prev, curr) {
        return prev.map(function(val, index) {
            return {
                x: val.x,
                y: val.y + curr[index].y
            }
        });
    });
}

Assumes arrays are sorted and contain all values of x in order 1..n with no gaps.

Kind of requires ES5. This can be swapped out for _ which gives this kind of functionality in a cross browser manner.

With underscore it is

function createOutput() {
    return _.reduce(arguments, function (memo, arr) {
        return _.map(memo, function(val, index) {
            return { x: val.x, y: val.y + arr[index].y };
        });
    });
}
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜