`reduce` with partial application caches results?
JamesRamm opened this issue · comments
I have found some odd behaviour in reduce
.
Consider this code::
const tasks = [
{ status: 'To Do' },
{ status: 'Complete' },
{ status: 'To Do' },
{ status: 'Complete' },
{ status: 'Paused' },
{ status: 'Complete' },
{ status: 'Not Ready' },
{ status: 'In Progress' },
];
const tasksReducer = (acc, current) => {
const key = current.status;
acc[key] = acc[key]
? { count: acc[key].count + 1, status: key }
: { count: 1, status: key };
return acc;
};
const groupByStatus = reduce(tasksReducer, {})
// Causes count to be doubled
groupByStatus(tasks)
groupByStatus(tasks)
It is grouping the tasks by their status (I know there are functions in ramda to do this - this is just to demonstrate the odd behaviour).
If I call groupByStatus(tasks)
once, I get the right result (e.g. The first group is {"count": 2, "status": "To Do"}
).
However, if I call it multiple times, the count doubles each time it is called. This seems to be related to partially applying arguments to reduce
because I do not reproduce the issue if I do this:
reduce(tasksReducer, {}, tasks)
reduce(tasksReducer, {}, tasks)
That's because you're mutating your accumulator, you can get the desired result by doing:
const tasksReducer = (acc, current) => {
const key = current.status;
return R.pipe(
R.mergeRight({ [key]: { status: key, count: 0 }}), // create the default value
R.modifyPath([key, 'count'], R.inc) // increase the count by 1
)(acc);
};