Skip to content

Instantly share code, notes, and snippets.

@jmcook1186
Last active February 9, 2024 13:51
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jmcook1186/b700c6426edc3ffdb35fe096c41241e7 to your computer and use it in GitHub Desktop.
Save jmcook1186/b700c6426edc3ffdb35fe096c41241e7 to your computer and use it in GitHub Desktop.
aggregate-metrics-array
const tree = {
name: "Root",
children: [{
name: "A",
energy: [40, 40, 40],
carbon: [10, 10, 10],
children: [{
name: "C",
carbon: [35, 35, 35],
energy: [10, 10, 10],
children: [
{
name: "E",
carbon: [50, 50, 50],
energy: [10, 10, 10],
children: []
}, {
name: "F",
energy: [20, 20, 20],
carbon: [33, 33, 33],
children: []
}]
},
{
name: "D",
energy: [30, 30, 30],
carbon: [35, 35, 35],
children: []
}
]
},
{
name: "B",
energy: [40, 40, 40],
carbon: [10, 10, 10],
children: []
}
]
};
let context = {
metrics: ['carbon', 'energy']
}
function hasChildren(tree) {
if (tree['children'].length > 0) {
return true
}
}
function getChildren(tree) {
return tree['children']
}
/** */
function aggregateTimeSeries(tree, context) {
// check if root has children
if (hasChildren(tree)) {
// iterate through child nodes
getChildren(tree).forEach(node => {
// if the child has children, start recursive call to aggregate()
if (hasChildren(node)) {
aggregateTimeSeries(node, context)
}
context['metrics'].forEach(metric => {
if (tree[`aggregated-${metric}`]) {
if (node[`aggregated-${metric}`]) {
tree[`aggregated-${metric}`] = sumArrays(tree[`aggregated-${metric}`], node[`aggregated-${metric}`])
} else {
tree[`aggregated-${metric}`] = sumArrays(tree[`aggregated-${metric}`], node[`${metric}`] ?? new Array(node[`aggregated-${metric}`].length).fill(0));
}
}
else {
if (node[`aggregated-${metric}`]) {
tree[`aggregated-${metric}`] = sumArrays(tree[`${metric}`] ?? new Array(node[`aggregated-${metric}`].length).fill(0), node[`aggregated-${metric}`])
} else {
tree[`aggregated-${metric}`] = sumArrays(tree[`${metric}`] ?? new Array(node[`${metric}`].length).fill(0), node[`${metric}`])
}
}
})
})
}
return tree
}
/** Sums each time series into a single-value total */
function aggregateOverTime(tree, context) {
if (hasChildren(tree)) {
// iterate through child nodes
getChildren(tree).forEach(node => {
// if the child has children, start recursive call to this func
if (hasChildren(node)) {
aggregateOverTime(node, context)
}
context['metrics'].forEach(metric => {
// sum metrics (from this node only, not including its children) and aggregated metrics (includes all children)
if (tree[`${metric}`]) {
tree[`total-${metric}`] = tree[`${metric}`].reduce((a, b) => a + b, 0)
}
if (tree[`aggregated-${metric}`]) {
tree[`total-aggregated-${metric}`] = tree[`aggregated-${metric}`].reduce((a, b) => a + b, 0)
}
if (node[`${metric}`]) {
node[`total-${metric}`] = node[`${metric}`].reduce((a, b) => a + b, 0)
}
if (node[`aggregated-${metric}`]) {
node[`total-aggregated-${metric}`] = node[`aggregated-${metric}`].reduce((a, b) => a + b, 0)
}
})
})
}
return tree
}
/** element-wise addition of two arrays */
function sumArrays(a, b) {
return a.map((element, idx) => { return element + b[idx] })
}
const tempTree = aggregateTimeSeries(tree, context)
const newTree = aggregateOverTime(tempTree, context)
console.log(newTree)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment