Reduce over Objects

For the following data set, calculate the score average only for available widgets.

const widgets = [
{
score: 123,
available: false,
name: 'Widget 1'
},
{
score: 331,
available: true,
name: 'Widget 2'
},
...
]

Reduce with an object as accumulator

const calculate = ({ total, length }, score) => ({ total += score, length += 1 })
const init = { total: 0, length: 0 }

const { total, length } = widgets.filter(({ available }) => available)
.map(({ score }) => score)
.reduce(calculate, init)

const average = total / length;

Point-free Function Composition

const filter = predicate => arr => arr.filter(predicate);
const map = fn => arr => arr.map(fn);
const cursor = path => obj => obj[path];
const reduce = acc => init => arr => arr.reduce(acc, init);
const compose = (...fns) => arg => fns.reduceRight((arg, fn) => fn(arg), arg);
const combinator = f => g => h => arg => f(g(arg))(h(arg));

const sum = reduce((arr, elem) => arr + elem)(0);
const length = arr => arr.length;
const divide = x => y => x / y;

const calculate = compose(
combinator(divide)(sum)(length),
map(cursor('score')),
filter(cursor('available'))
);

const average = calculate(widgets);

Using Reducers

const reducers = {
filter: predicate => (acc, elem) => predicate(item) ? acc.concat([elem]) : acc,
map: fn => (acc, elem) => acc.concat([fn(elem)]),
}

const availableReducer = reducers.filter(({ available }) => available);
const scoreReducer => reducers.map(({ score }) => score);

const { total, length } = widgets.reduce(availableReducer, [])
.reduce(scoreReducer, [])
.reduce(calculate, init);

Using home-grown Transducers

const transducers = {
filter: predicate => step => (acc, elem) => predicate(item) ? step(acc, item) : acc,
map: fn => step => (acc, elem) => step(acc, fn(elem))
}

const availableTransducer = transducers.filter(({ available }) => available);
const scoreTransducer => transducers.map(({ score }) => score);

const reducer = availableTransducer(scoreTransducer(calculate));

const { total, length } = widgets.reduce(reducer, init);

Using Ramda Transducers

import { compose, filter, map, transduce } from 'ramda';

const prepare = compose(filter(({ available }) => available), map(({ score }) => score));

const { total, length } = transduce(
prepare,
calculate,
init,
widgets
)