Function versus procedural aggregation

Benchmark created on


Setup

var data = [];

function randInt(lo, hi) {
	return Math.floor(Math.random()*(hi-lo+1))+lo;
}
function randDate() {
	const m = randInt(1,12)
	const d = randInt(1,30)
	return `2023-${m}-${d}`
}

function randAsset() {
	const assets = ['usd', 'btc', 'eth', 'mro', 'nya', 'dog'];
	return assets[randInt(0,assets.length-1)]
}
for(let i=0; i < 100000; i++) {
	data.push({
		date: randDate(),
		asset: randAsset(),
		foo: 'bar',
		rolling_amount: randInt(0,1000).toString(),
	});
}

Test runner

Ready to run.

Testing in
TestOps/sec
functional
const datedEntries = data.filter(e => !!e && !!e.date && !!e.asset)

const entriesBydate = Object.groupBy(datedEntries, e => e.date);

Object.fromEntries(
   Object.entries(entriesBydate).map(
     ([date, entries]) => ([
     date, 
     Object.fromEntries(entries.map(e => [e.asset, e.rolling_amount]))
   ]))
);
ready
procedural
const dateIndexedBalances = {};
  for (const entry of data) {
    if (!entry || !entry.date) {
      continue;
    }
    if (!dateIndexedBalances[entry.date]) {
      dateIndexedBalances[entry.date] = {};
    }
    if (entry.asset) {
      dateIndexedBalances[entry.date][entry.asset] = entry.rolling_amount;
    }
  }

ready
combo
const datedEntries = data.filter(e => !!e && !!e.date && !!e.asset)

const entriesBydate = Object.groupBy(datedEntries, e => e.date);

for(const date in entriesBydate) {
	entriesBydate[date] = Object.fromEntries(entriesBydate[date].map((e) => [e.asset, e.rolling_amount]));
}
ready

Revisions

You can edit these tests or add more tests to this page by appending /edit to the URL.