问题
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}]
How 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.
回答1:
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.
回答2:
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 };
});
});
}
来源:https://stackoverflow.com/questions/6383222/aggregating-object-values-of-javascript-arrays