frontmatter

Ramda's mapAccum function

February 01, 2022

Ramdajs is JavaScript library for functional programming. Ramda makes it easy to create functional pipelines, where the output of one function is piped into the input of the next. Ramda allows you to write complex logic by combining simple functions. Ramda functions never mutate data so you won’t have to think about shared mutable state and all functions are free from side-effects. They don’t interact with any state outside of the function. This makes the code predictable and easier to understand.

The missing child of map and reduce

JavaScript developers are familiar with the build-in array methods map and reduce and Ramda’s mapAccum function is closely related to them. It is like reduce in that it outputs an accumulator, a value that is updated by each item in the array. and similar to map it outputs all the intermediate values.

Code examples

Ramdas map and reduce functions are not part of the array prototype. Instead they accept the array as the last argument.

const integers = [1, 2, 3, 4];
const addOne = value => value + 1;
map(addOne, integers) // [1 + 1, 2 + 1, 3 + 1, 4 + 1] => [2, 3, 4, 5]
const addToAcc = (value, acc) => value + acc;
reduce(addToAcc, 0, integers) // 0 + 1 + 2 + 3 + 4 => 10

Ramdas mapAccum function accepts a function that takes a value and accumulator and outputs a tuple of value and accumulator. mapAccum outputs a tuple of the calculated value and an array of the intermediate values of the accumulator.

const integers = [1, 2, 3, 4];
const mapAccumFn = (value, acc) => [value + acc, value + acc];
mapAccum(mapAccumFn, 0, integers); // [10, [1, 3, 6, 10]]

You can play around with these functions in the Ramda playground.

A random walk with mapAccum

Here’s a random walk implemented using Ramda’s mapAccum function.

function moveRandomly(point: [number, number]) {
const directions = {
n: ([x, y]) => [x, y + 1],
ne: ([x, y]) => [x + 1, y + 1],
e: ([x, y]) => [x + 1, y],
se: ([x, y]) => [x + 1, y - 1],
s: ([x, y]) => [x, y - 1],
sw: ([x, y]) => [x - 1, y - 1],
w: ([x, y]) => [x - 1, y],
nw: ([x, y]) => [x - 1, y + 1],
}
function getRandomProperty(obj) {
const keys = Object.keys(obj)
const randomKey = keys[Math.floor(Math.random() * keys.length)]
return obj[randomKey]
}
return [
getRandomProperty(directions)(point),
getRandomProperty(directions)(point),
]
}
const startingPoint = [25, 25]
const movements = Array(3000).fill(null)
const [, randomWalk] = mapAccum(moveRandomly, startingPoint, movements)

You can use the generated list to create a string that draws a line in an svg.
This example uses JSX.

const pathD = randomWalk.reduce(
(acc, point) => `${acc} L ${point[0]} ${point[1]}`, 'M 25 25'
)
return (
<svg viewBox="0 0 50 50" xmlns="http://www.w3.org/2000/svg">
<path d={pathD} fill="transparent" stroke="black" stroke-width="0.1" />
</svg>
)

Profile picture

Written by Heiner Behrends.

heinerbehrends.eu is home to my portfolio and blog. Here I present personal projects focused on interactivity and blog posts that document my learning progress. Feel free to check out my portfolio. You can follow me on Twitter.

© 2022, Built with love by flyfi
Check out my portfolio on the home page.