let\'s begin with the simple form.
Imagine you have a simple dataset like this one: you want to retrieve the cumulative amounts for each asset.
First I would filter (ar
As suggested in the comments, you can use a simple query:
E1:
=query(A:D,"select A,B,C,sum(D) where A is not null group by A,B,C ",1)
The problem, as I understand it, is not exponential. The complexity is still linear, one is simply adding more criteria when scanning through the available data.
The technique is to accumulate the data based on the fields that you're trying to group to achieve the subtotals. For example, if you want to group by year/month, then all that is needed is the year/month to define the subtotal buckets. Eg, you will have a bucket for '20181', '20182', '20183', etc. As you loop through the entries in the array, you will use the year/month to identify the bucket and to add the entries value into that subtotal bucket.
If you are including additional fields as part of the subtotal grouping (eg, currency and year/month), then it is simply a matter of adjusting the bucket names to include both currency and year/month. Ie, your subtotal buckets will now be '~cad~20181~', '~cad~20182~', '~eur~20181~', etc. This uniquely identifies the subtotal buckets by currency and year/month. Then, as before, when looping through the entries in the array, you are taking the values from the array entry to identify the currency and year/month bucket that the value belongs... Note that the tildes are arbitrary delimiters to separate the field values when constructing the subtotal bucket names.
a = [
{geo:"cad", ym:20182, value:3},
{geo:"eur", ym:20181, value:1},
{geo:"pop", ym:20182, value:2},
{geo:"usd", ym:20181, value:3},
{geo:"cad", ym:20182, value:3},
{geo:"sol", ym:20181, value:1},
{geo:"cad", ym:20181, value:3},
{geo:"pop", ym:20182, value:2},
{geo:"pop", ym:20181, value:5}
];
var result = a.reduce( (totals, entry) => {
let key = '~' + entry.geo + '~' + entry.ym + '~';
totals[key] = ( totals[key] || 0 ) + entry.value;
return totals;
}, {} );
console.log( result );
Variation of the code using a for
loop.
arr = [
{geo:"cad", ym:20182, value:3},
{geo:"eur", ym:20181, value:1},
{geo:"pop", ym:20182, value:2},
{geo:"usd", ym:20181, value:3},
{geo:"cad", ym:20182, value:3},
{geo:"sol", ym:20181, value:1},
{geo:"cad", ym:20181, value:3},
{geo:"pop", ym:20182, value:2},
{geo:"pop", ym:20181, value:5}
];
result = {};
// Loop through each entry in arr
for ( let i = 0; i < arr.length; i++ ) {
// Create the subtotal bucket name based on the fields
// defining the grouping.
let key = '~' + arr[ i ].geo + '~' + arr[ i ].ym + '~';
// Now that we know which subtotal bucket arr[i].value
// belongs, let's add it to the bucket.
result[ key ] = (result[ key ] || 0 ) + arr[ i ].value ;
}
console.log( result );
In both examples, I've collected the values into an object with each property representing a subtotal bucket. A Map object can be used as well, but is less clear in exemplifying the critical concept of naming the subtotal buckets according to how the subtotals are to be grouped...
Hope this helps.