Reputation: 7045
What is the cleanest way to reduce those array ?
data = {
id: [1, 1, 1, 3, 3, 4, 5, 5, 5, ...]
v: [10,10,10, 5, 10 ...]
}
For each id there is a v corresponding. What I want is sum up v for each id. In this example the result should be
data = {
id: [1, 3, 4, 5, ...]
v: [30, 15, ...]
}
Upvotes: 6
Views: 107
Reputation: 6286
I would go for the Array.prototype.reduce() ,simple and elegant solution
var ids = [1, 1, 1, 3, 3, 3, 3, 4, 5, 6, 6, 6],
v = [10, 10, 10, 5, 10, 10, 10, 404, 505, 600, 60, 6],
data = {};
data.v = [];
data.ids = ids.reduce(function(a, b, index) {
if (a.indexOf(b) < 0) a.push(b);
if (!data.v[a.indexOf(b)]) data.v[a.indexOf(b)] = 0;
data.v[a.indexOf(b)] += v[index];
return a;
}, []);
https://jsfiddle.net/2ssbngLr/
Upvotes: 3
Reputation: 386660
This is a solution for ordered id
with Array.prototype.reduce()
.
var data = {
id: [1, 1, 1, 3, 3, 4, 5, 5, 5],
v: [10, 10, 10, 5, 10, 7, 8, 10, 13]
},
result = { id: [], v: [] };
data.id.reduce(function (r, a, i) {
if (r === a) {
result.v[result.v.length - 1] += data.v[i];
} else {
result.id.push(a);
result.v.push(data.v[i]);
}
return a;
}, -1);
document.write('<pre>' + JSON.stringify(result, 0, 4) + '</pre>');
Or a in situ version
var data = {
id: [1, 1, 1, 3, 3, 4, 5, 5, 5],
v: [10, 10, 10, 5, 10, 7, 8, 10, 13]
};
void function (d) {
var i = 1;
while (i < d.id.length) {
if (d.id[i - 1] === d.id[i]) {
d.id.splice(i, 1);
d.v[i - 1] += d.v.splice(i, 1)[0];
continue;
}
i++;
}
}(data);
document.write('<pre>' + JSON.stringify(data, 0, 4) + '</pre>');
Upvotes: 1
Reputation: 5637
Some people have posted some good solutions so far, but I haven't really seen one that does exactly what you're looking for. Here is one that takes your specific object and returns an object of the same format, but meeting your requirements and reduced.
// Your data object
data = {
id: [1, 1, 1, 3, 3],
v: [10,10,10, 5, 10]
}
// Assuming obj consists of `id` and `v`
function reduce(obj){
// We create our reduced object
var reducedObj = {
id: [],
v: []
}
// Next we create a hash map to store keys and values
var map = {};
for(var i=0; i<obj.id.length; ++i){
// If this key doesn't exist, create it and give it a value
if(typeof map[parseInt(obj.id[i])] === 'undefined'){
map[parseInt(obj.id[i])] = 0;
}
// Sum all of the values together for each key
map[parseInt(obj.id[i])] += parseInt(obj.v[i]);
}
// Now we map back our hashmap to our reduced object
for(var ele in map){
reducedObj.id.push(ele);
reducedObj.v.push(map[ele]);
}
// Return our new reduced object
return reducedObj;
}
var myReducedObject = reduce(data);
console.log(myReducedObject);
Upvotes: 1
Reputation: 207527
If the ids are always in order, a simple for loop can solve it. There is no need to get overly complicated.
data = {
id: [1, 1, 1, 3, 3, 4, 5, 5, 5],
v: [10, 10, 10, 5, 10, 1, 2, 3, 4]
};
var result = {
id: [],
v: []
};
(function() {
var ids = data.id,
vals = data.v,
lastId = ids[0],
runningTotal = vals[0];
for (var i = 1; i < ids.length; i++) {
if (lastId === ids[i]) {
runningTotal += vals[i];
}
if (lastId !== ids[i] || i + 1 === ids.length) {
result.id.push(lastId);
result.v.push(runningTotal);
lastId = ids[i];
runningTotal = vals[i];
}
}
}());
console.log(result);
Upvotes: 1
Reputation: 53991
One way of doing this, given two arrays of equal length would be to map/reduce them:
const ids = [1, 1, 1, 3, 3];
const vs = [10,10,10,5,10];
const reduced = ids
.map((val, i) => ({ id: val, value: vs[i] }))
.reduce((agg, next) => {
agg[next.id] = (agg[next.id] || 0) + next.value;
return agg;
}, {});
console.log(reduced);
// Object {1: 30, 3: 15}
Working example: https://jsfiddle.net/h1o5rker/1/
Upvotes: 3
Reputation: 413
var data={
id: [1,1,1,10,123,4531],
v:[123,123,53,223,11,11,11]
},
_v = data.v, vinit;
document.write(data.v+'<br>');
for(var i=0;i<_v.length;i++){
vinit = _v[i];
for(var j=i+1; j<=_v.length;j++){
if(_v[j]===vinit){
delete _v[j];
}
}
};
document.write(data.v);
var data={
id: [1,1,1,10,123,4531],
v:[123,123,53,223,11,11,11,...]
},
_v = data.v, vinit;
for(var i=0;i<_v.length;i++){
vinit = _v[i];
for(var j=i+1; j<=_v.length;j++){
if(_v[j]===vinit){
delete _v[j];
}
}
}
the above code is just for the v but you can simultaneously reduce the repeating elements for id too by introducing some more variables
in the snippet you can see that there are the extra commas in the second line which shows that those elements were deleted
Upvotes: 1
Reputation: 3207
I think it can be accomplished with reduce
var data = {
id: [1, 1, 1, 3, 3],
v: [10, 10, 10, 5, 10]
}
var sumsObjs = data.v.reduce(function(sum, val, index) {
var id = data.id[index];
if (sum[id] !== undefined) {
sum[id] = sum[id] + val;
} else {
sum[id] = val;
}
return sum;
}, {});
console.log(sumsObjs);
<script src="https://getfirebug.com/firebug-lite-debug.js"></script>
Upvotes: 2