Reducing Or Whatever

Benchmark created by joshuahiggins on


Setup

const victorianSlang = [
      {
          term: 'doing the bear',
          found: true,
          popularity: 108,
      },
      {
          term: 'katterzem',
          found: false,
          popularity: null,
      },
      {
          term: 'bone shaker',
          found: true,
          popularity: 609,
      },
      {
          term: 'smothering a parrot',
          found: false,
          popularity: null,
      },
      {
          term: 'damfino',
          found: true,
          popularity: 232,
      },
      {
          term: 'rain napper',
          found: false,
          popularity: null,
      },
      {
          term: 'donkey’s breakfast',
          found: true,
          popularity: 787,
      },
      {
          term: 'rational costume',
          found: true,
          popularity: 513,
      },
      {
          term: 'mind the grease',
          found: true,
          popularity: 154,
      },
  
  ];

Test runner

Ready to run.

Testing in
TestOps/sec
not using reduce at all (imperative loop)
let popularitySum = 0;
let itemsFound = 0;
const len = victorianSlang.length;
let item = null;
for (let i = 0; i < len; i++) {
    item = victorianSlang[i];
    if (item.found) {
        popularitySum = item.popularity + popularitySum;
        itemsFound = itemsFound + 1;
    }
}
const averagePopularity = popularitySum / itemsFound;
ready
easy mode: filter, map, and sum
function isFound(item) {
    return item.found;
};

function getPopularity(item) {
    return item.popularity;
}

function addScores(runningTotal, popularity) {
    return runningTotal + popularity;
}

const foundSlangTerms = victorianSlang.filter(isFound);
const popularityScores = foundSlangTerms.map(getPopularity);
const scoresTotal = popularityScores.reduce(addScores, 0);

const averagePopularity = scoresTotal / popularityScores.length;
ready
easy mode ii: multiple accumulator values
function isFound(item) {
    return item.found;
};

function getPopularity(item) {
    return item.popularity;
}

function addScores({totalPopularity, itemCount}, popularity) {
    return {
        totalPopularity: totalPopularity + popularity,
        itemCount:       itemCount + 1,
    };
}

const initialInfo    = {totalPopularity: 0, itemCount: 0};
const popularityInfo = victorianSlang.filter(isFound)
    .map(getPopularity)
    .reduce(addScores, initialInfo);

const {totalPopularity, itemCount} = popularityInfo;
const averagePopularity = totalPopularity / itemCount;
ready
point-free function composition
const filter  = p => a => a.filter(p);
const map     = f => a => a.map(f);
const prop    = k => x => x[k];
const reduce  = r => i => a => a.reduce(r, i);
const compose = (...fns) => (arg) => fns.reduceRight((arg, fn) => fn(arg), arg);

const B1 = f => g => h => x => f(g(x))(h(x));
const sum = reduce((a, i) => a + i)(0);
const length = a => a.length;
const div = a => b => a / b;
const calcPopularity = compose(
    B1(div)(sum)(length),
    map(prop('popularity')),
    filter(prop('found')),
);

const averagePopularity = calcPopularity(victorianSlang);
ready
single pass with cumulative average calculation
function averageScores({avg, n}, slangTermInfo) {
    if (!slangTermInfo.found) {
        return {avg, n};
    }
    return {
        avg: (slangTermInfo.popularity + n * avg) / (n + 1),
        n:   n + 1,
    };
}

const initialVals       = {avg: 0, n: 0};
const averagePopularity = victorianSlang.reduce(averageScores, initialVals).avg;
ready
the right answer is always in the comments
const averagePopularity = victorianSlang
  .filter(term => term.found)
  .reduce((avg, term, _, src) => avg + term.popularity/src.length, 0);
ready

Revisions

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

  • Revision 1: published by joshuahiggins on