Ramda tutorial
last modified July 7, 2020
Ramda tutorial shows how to work with the Ramda library, which provides tools for advanced functional programming in JavaScript. In this tutorial we use terms list and array interchangeably.
Ramda
Ramda is a practical functional library for JavaScript programmers. The library focuses on immutability and side-effect free functions. Ramda functions are also automatically curried, which allows to build up new functions from old ones simply by not supplying the final parameters.
In this tutorial we work with Ramda in a Node application.
Setting up Ramda
First, we install Ramda.
$ nodejs -v v12.16.1
We use Node version 12.16.1.
$ npm init -y
We initiate a new Node application.
$ npm i ramda
We install Ramda with npm i ramda
command.
const R = require('ramda');
By convention, the library uses R letter.
Ramda add, subtract functions
The add()
function adds two values, and the subtract()
function subtracts two values.
const R = require('ramda'); console.log(R.add(2, 5)); console.log(R.subtract(2, 5)); let res = R.add(R.add(2, 5), R.subtract(2, 10)); console.log(res);
The example uses both add()
and subtract()
functions.
let res = R.add(R.add(2, 5), R.subtract(2, 10));
Here we combine these functions.
$ node add_sub.js 7 -3 -1
This is the output.
Ramda flip function
The flip()
function returns a new function from the
supplied one where its arguments are reversed.
const R = require('ramda'); let val = R.subtract(2, 10); console.log(val); let val2 = R.flip(R.subtract)(2, 10); console.log(val2);
The example reverses the arguments of the subtract()
function
with flip()
.
$ node flipfun.js -8 8
This is the output.
Ramda call function
The call()
function invokes a provided function on
arguments separated by comma.
const R = require('ramda'); let res = R.call(R.add, 1, 2); console.log(res); console.log(R.call(R.repeat, 'x')(5)); R.call(console.log, [1, 2, 3]);
The example uses the call()
function.
let res = R.call(R.add, 1, 2);
We call the add()
function to add two integers.
console.log(R.call(R.repeat, 'x')(5));
We call the repeat()
function to generate a list of five
'x' letters.
R.call(console.log, [1, 2, 3]);
Finally, we use the call()
function to output the list.
$ node calling.js 3 [ 'x', 'x', 'x', 'x', 'x' ] [ 1, 2, 3 ]
This is the output.
Ramda apply function
The apply()
function invokes a provided function on a list
of arguments.
const R = require('ramda'); let nums = [3, 5, 7, 8, 2, 1]; let res = R.apply(Math.min, nums); console.log(res); let res2 = R.apply(Math.max, nums); console.log(res2);
The example uses the apply()
function to compute minimum
and maximum.
let res = R.apply(Math.min, nums);
We invoke the Math.min
function on a nums
list.
We get the minimum from the values.
$ node applyfun.js 1 8
We get the minimum and maximum.
Ramda automatic currying
Currying is the process of transforming a function that expects multiple parameters into another function that, when supplied fewer parameters, returns a new function that awaits the remaining ones.
const R = require('ramda'); let addOneToAll = R.map(R.add(1)); let res = addOneToAll([1,2,3]); console.log(res);
In the example, we create a addOneToAll()
function that
increments each element in the list by one.
$ node currying.js [ 2, 3, 4 ]
This is the output.
Ramda head, tail, init, last functions
The head()
returns the first element of the given list
or string. The tail()
returns all but the first element of
the given list or string. The init()
returns all but the
last element of the given list or string. The last()
returns the last element of the given list or string.
const R = require('ramda'); let nums = [2, 4, 6, 8, 10]; console.log(R.head(nums)); console.log(R.tail(nums)); console.log(R.init(nums)); console.log(R.last(nums));
The example uses head()
, tail()
, init()
,
and last()
functions on an array of values.
$ node head_tail.js 2 [ 4, 6, 8, 10 ] [ 2, 4, 6, 8 ] 10
This is the output.
Ramda length function
The length()
function returns the number of elements in
the list.
const R = require('ramda'); let nums = [1, 2, 2, 2, 3, 3, 4, 5, 5, 5, 6, 7]; let n1 = R.length(nums); console.log(n1); let n2 = R.length(R.uniq(nums)); console.log(n2);
In the example, we calculate the number of elements in list and the number of unique elements in the list.
$ node lengthfn.js 12 7
There are twelve elements in the list and seven unique elements in the list.
Ramda prop function
The prop()
function returns the specified property of
an object if it exists.
const R = require('ramda'); console.log(R.prop('name', { name: 'John', age: 25 })); console.log(R.prop('age', { name: 'John', age: 25 }));
With the prop()
function, we get the values of the
name
and age
properties.
$ node propfun.js John 25
This is the output.
Ramda pluck function
The pluck()
function returns a new list by plucking the
specified property off all objects in the list supplied.
const R = require('ramda'); const users = [ { name: 'John', age: 25 }, { name: 'Lenny', age: 51 }, { name: 'Andrew', age: 43 }, { name: 'Peter', age: 81 }, { name: 'Anna', age: 43 }, { name: 'Albert', age: 76 }, { name: 'Adam', age: 47 }, { name: 'Robert', age: 72 } ]; console.log(R.pluck('age', users)); console.log(R.pluck('name', users));
With the pluck()
function, we take the name
and age
properties and form two new lists.
$ node plucking.js [ 25, 51, 43, 81, 43, 76, 47, 72 ] [ 'John', 'Lenny', 'Andrew', 'Peter', 'Anna', 'Albert', 'Adam', 'Robert' ]
In the following example we will work with the formed list.
const R = require('ramda'); const users = [ { name: 'John', age: 25 }, { name: 'Lenny', age: 51 }, { name: 'Andrew', age: 43 }, { name: 'Peter', age: 81 }, { name: 'Anna', age: 43 }, { name: 'Albert', age: 76 }, { name: 'Adam', age: 47 }, { name: 'Robert', age: 72 } ]; let maxAge = R.apply(Math.max, R.pluck('age', users)); // let maxAge = Math.max(... R.pluck('age', users)); console.log(`The oldest person is ${maxAge} years old.`);
In the example we find out the oldest age of a person.
let maxAge = R.apply(Math.max, R.pluck('age', users));
By invoking the Math.max()
function on a list of ages,
we get the oldest age.
// let maxAge = Math.max(... R.pluck('age', users));
An alternative commented solution uses a spread operator instead of
the apply()
function.
$ node plucking2.js The oldest person is 81 years old.
This is the output.
Ramda split list
With splitEvery()
function, we can split a list into
chunks of specified length.
const R = require('ramda'); let nums = [1, 2, 3, 4, 5, 6]; console.log(R.splitEvery(2, nums)); console.log(R.splitEvery(3, nums));
In the example, we split the array into chunks of 2 and 3 elements.
$ node chunks.js [ [ 1, 2 ], [ 3, 4 ], [ 5, 6 ] ] [ [ 1, 2, 3 ], [ 4, 5, 6 ] ]
This is the output.
Ramda contains function
The contains()
function returns true if the specified
value is in the list.
const R = require('ramda'); const users = [ { name: 'John', age: 25 }, { name: 'Lenny', age: 51 }, { name: 'Andrew', age: 43 }, { name: 'Peter', age: 81 }, { name: 'Anna', age: 43 }, { name: 'Albert', age: 76 }, { name: 'Adam', age: 47 }, { name: 'Robert', age: 72 } ]; let isJohn = R.contains('John', R.pluck('name', users)); if (isJohn) { console.log('There is John in the list'); }
In the example we check if the specified user is in the list.
let isJohn = R.contains('John', R.pluck('name', users));
First, we use the pluck()
function to form a list from
the name
property. Then we check if 'John' is in the
list with contains()
.
$ node containsfun.js There is John in the list
This is the output.
Ramda range function
The range()
function returns a list of numbers from the
start value (inclusive) to the end value (exclusive).
const R = require('ramda'); console.log(R.range(1, 10)); let vals = R.range(2, 12); vals.forEach(x => console.log(x));
The example shows how to use the range()
function.
console.log(R.range(1, 10));
In this line, we create a list of 1..9 integers. We print them to the console.
let vals = R.range(2, 12); vals.forEach(x => console.log(x));
Here we generate a list of 2..11 values. We go over the list with
the forEach()
function.
$ node rangefun.js [ 1, 2, 3, 4, 5, 6, 7, 8, 9 ] 2 3 4 5 6 7 8 9 10 11
This is the output.
Ramda sum function
The sum()
function sums all the elements of a list.
const R = require('ramda'); let nums = [2, 4, 6, 8, 10]; console.log(R.sum(nums)); console.log(R.sum(R.range(1, 11)));
The example uses the sum()
function to sum integer values.
let nums = [2, 4, 6, 8, 10]; console.log(R.sum(nums));
Here we sum the values of the nums
array.
console.log(R.sum(R.range(1, 11)));
In this line we sum values of a list generated by the range()
function.
$ node summation.js 30 55
This is the output.
Ramda product function
The product()
function multiplies together all the elements
of a list.
const R = require('ramda'); let nums = [2, 4, 6, 8, 10]; console.log(R.product(nums));
The example calculates the product of a list of integers.
$ node productfun.js 3840
This is the output.
Ramda sort, reverse functions
The sort()
function returns a copy of the list, sorted
according to the comparator function. The comparator function accepts
two values at a time and returns a negative number if the first value
is smaller, a positive number if it is larger, and zero if they are equal.
The reverse()
function returns a new list or string with
the elements or characters in reverse order.
const R = require('ramda'); let nums = [3, 1, 4, 2, 8, 5, 6]; console.log('sorting:') // sort ascending console.log(R.sort((x, y) => x - y , nums)); // sort descending console.log(R.sort((x, y) => y - x , nums)); console.log('reversing:') // reversing console.log(R.reverse(nums)); console.log(R.reverse('forest'));
The example sorts integers in ascending and descending order and reverses integers and a string.
$ node sort_reverse.js sorting: [ 1, 2, 3, 4, 5, 6, 8 ] [ 8, 6, 5, 4, 3, 2, 1 ] reversing: [ 6, 5, 8, 2, 4, 1, 3 ] tserof
This is the output.
We can also use the built-in R.lt
and R.gt
comparators.
const R = require('ramda'); let nums = [3, 1, 4, 2, 8, 5, 6]; console.log('sorting:') // sort ascending console.log(R.sort(R.comparator(R.lt), nums)); // sort descending console.log(R.sort(R.comparator(R.gt), nums));
The example sorts integers in ascending and descending order.
Ramda sortBy function
The sortBy()
function sort the list according to the
supplied function.
const R = require('ramda'); const users = [ { name: 'John', age: 25 }, { name: 'Lenny', age: 51 }, { name: 'Andrew', age: 43 }, { name: 'Peter', age: 81 }, { name: 'Anna', age: 43 }, { name: 'Albert', age: 76 }, { name: 'Adam', age: 47 }, { name: 'Robert', age: 72 } ]; console.log('Sorted by age:'); let sortedByAge = R.sortBy(R.prop('age'), users); console.log(sortedByAge); console.log('Sorted by name:'); let sortedByName = R.sortBy(R.prop('name'), users); console.log(sortedByName);
In the example, we sort the list of users by age
and
name
properties in ascending order.
$ node sorting_objects.js Sorted by age: [ { name: 'John', age: 25 }, { name: 'Andrew', age: 43 }, { name: 'Anna', age: 43 }, { name: 'Adam', age: 47 }, { name: 'Lenny', age: 51 }, { name: 'Robert', age: 72 }, { name: 'Albert', age: 76 }, { name: 'Peter', age: 81 } ] Sorted by name: [ { name: 'Adam', age: 47 }, { name: 'Albert', age: 76 }, { name: 'Andrew', age: 43 }, { name: 'Anna', age: 43 }, { name: 'John', age: 25 }, { name: 'Lenny', age: 51 }, { name: 'Peter', age: 81 }, { name: 'Robert', age: 72 } ]
This is the output.
Ramda find, findLast functions
The find()
function returns the first element of the list
which matches the predicate, or undefined if there is no match.
The findLast()
function returns the last element of the
list which matches the predicate, or undefined if no element matches.
const R = require('ramda'); const isPositive = x => x > 0; let values = [-1, 0, -4, 5, 6, -1, 9, -2] let val = R.find(isPositive, values); console.log(val); let val2 = R.findLast(isPositive, values); console.log(val2);
In the example, we find the first and last positive value.
const isPositive = x => x > 0;
The isPositive()
is a predicate function which returns
true for values greater than zero.
let val = R.find(isPositive, values);
With find()
, we find the first occurrence of a positive
number.
let val2 = R.findLast(isPositive, values);
With findLast()
, we find the last occurrence of a positive
number.
$ node finding.js 5 9
The first positive value is 5, the last 9.
In the following example, we use the find()
function on
a list of objects.
const R = require('ramda'); const users = [ { name: 'John', age: 25 }, { name: 'Lenny', age: 51 }, { name: 'Andrew', age: 43 }, { name: 'Peter', age: 81 }, { name: 'Anna', age: 43 }, { name: 'Albert', age: 76 }, { name: 'Adam', age: 47 }, { name: 'Robert', age: 72 }, { name: 'Robert', age: 26 }, ]; console.log(R.find(R.propEq('name', 'Robert'))(users)); console.log(R.find(R.propEq('age', 81))(users));
With the combination of find()
and propEq()
functions we look for users having specified attributes.
console.log(R.find(R.propEq('name', 'Robert'))(users));
Here we look for a person named Robert. There are two Roberts and the first match is returned.
$ node finding2.js { name: 'Robert', age: 72 } { name: 'Peter', age: 81 }
This is the output.
Ramda map function
The map()
function maps a provided function on each of
the container's values.
const R = require('ramda'); nums = [2, 4, 5, 6, 7, 8, 9]; let res = R.map(x => x * 2, nums); console.log(res); const isEven = x => x % 2 === 0; let res2 = R.map(isEven, nums); console.log(res2); let repeated = R.map(R.call, R.repeat(Math.random, 5)); console.log(repeated);
The example demonstrates the usage of map()
.
let res = R.map(x => x * 2, nums);
We map an anonymous function on the list of integers. A new list is generated where each of the value is multiplied by 2.
const isEven = x => x % 2 === 0; let res2 = R.map(isEven, nums);
Here we apply the isEven()
function on each of the elements.
The res2
is a list of true and false values. If we wanted
to pick only event numbers then we would use filter()
function.
let repeated = R.map(R.call, R.repeat(Math.random, 5));
In the third case, we generate a list of five random values.
$ node mapping.js [ 4, 8, 10, 12, 14, 16, 18 ] [ true, true, false, true, false, true, false ] [ 0.22019193556521865, 0.415950206671615, 0.8770997167119405, 0.23393806619678315, 0.8181008680173825 ]
This is the output.
Ramda filter function
The filter()
fuction filters a filterable (such as list
or plain object) according to the supplied predicate function.
(A predicate is a function that returns a boolean value).
const R = require('ramda'); nums = [-3, -1, 0, 2, 3, 4, 5, 6, 7] let res = R.filter(x => x > 0, nums); console.log(res); let res2 = R.filter(x => x < 0, nums); console.log(res2); const isEven = x => x % 2 === 0; let filtered = R.filter(isEven, nums); console.log(filtered);
In the example, we have a list of integer values. We use the filter()
function to filter out positive, negative, and even values.
let res = R.filter(x => x > 0, nums);
The filter()
function in this line takes an anonymous
function that returns true for all values greater than zero. The predicate
is then applied on each element of the list. This way we form a new list
containing only positive values.
$ node filtering.js [ 2, 3, 4, 5, 6, 7 ] [ -3, -1 ] [ 0, 2, 4, 6 ]
This is the output.
In the following example we apply the filter()
function
on a list of users.
const R = require('ramda'); // senior is a person who is 70+ const users = [ { name: 'John', age: 25 }, { name: 'Lenny', age: 51 }, { name: 'Andrew', age: 43 }, { name: 'Peter', age: 81 }, { name: 'Anna', age: 43 }, { name: 'Albert', age: 76 }, { name: 'Adam', age: 47 }, { name: 'Robert', age: 72 } ]; console.log(R.filter(user => user.age >= 70, users));
The example filters out senior users. We define a senior as someone who is 70 and older.
$ node filtering2.js [ { name: 'Peter', age: 81 }, { name: 'Albert', age: 76 }, { name: 'Robert', age: 72 } ]
We have three senior users.
The reject function
The reject()
is a complement to the filter()
.
It excludes elements of a filterable for which the predicate returns true.
const R = require('ramda'); const users = [ { name: 'John', city: 'London', born: '2001-04-01' }, { name: 'Lenny', city: 'New York', born: '1997-12-11' }, { name: 'Andrew', city: 'Boston', born: '1987-02-22' }, { name: 'Peter', city: 'Prague', born: '1936-03-24' }, { name: 'Anna', city: 'Bratislava', born: '1973-11-12' }, { name: 'Albert', city: 'Bratislava', born: '1940-18-19' }, { name: 'Adam', city: 'Trnava', born:'1983-12-01' }, { name: 'Robert', city: 'Bratislava', born: '1935-05-15' }, { name: 'Robert', city: 'Prague', born:'1998-03-14' } ]; let res = R.reject(R.propEq('city', 'Bratislava'))(users); console.log(res); let res2 = R.filter(R.propEq('city', 'Bratislava'))(users); console.log(res2);
In the example, we use the reject()
function to form
a new list of objects that does not contain Bratislava city. We also use the
filter()
function to form a new list of objects that
contain Bratislava city.
$ node rejecting.js [ { name: 'John', city: 'London', born: '2001-04-01' }, { name: 'Lenny', city: 'New York', born: '1997-12-11' }, { name: 'Andrew', city: 'Boston', born: '1987-02-22' }, { name: 'Peter', city: 'Prague', born: '1936-03-24' }, { name: 'Adam', city: 'Trnava', born: '1983-12-01' }, { name: 'Robert', city: 'Prague', born: '1998-03-14' } ] [ { name: 'Anna', city: 'Bratislava', born: '1973-11-12' }, { name: 'Albert', city: 'Bratislava', born: '1940-18-19' }, { name: 'Robert', city: 'Bratislava', born: '1935-05-15' } ]
This is the output. The first list contains all objects that do not contain the Bratislava city attribute.. The second one contains only objects having Bratislava city attribute.
The partition function
The partition()
function divides filterable into a two
separate objects: one that satisfies the predicate and one that does not.
const R = require('ramda'); let nums = [4, -5, 3, 2, -1, 7, -6, 8, 9]; let [ neg, pos ] = R.partition(e => e < 0, nums); console.log(neg); console.log(pos);
With the partition()
function we split the list of integers
into two separate lists: negative and positive.
$ node partitionfun.js [ -5, -1, -6 ] [ 4, 3, 2, 7, 8, 9 ]
The first list contains negative values, the second list positive.
Ramda groupBy function
The groupBy()
function splits a list into sub-lists
stored in an object, based on the result of calling a String-returning
function on each element, and grouping the results according to
values returned.
const R = require('ramda'); let students = [ { name: 'Adam', score: 84 }, { name: 'Eddy', score: 58 }, { name: 'Peter', score: 69 }, { name: 'Roman', score: 93 }, { name: 'Jane', score: 56 }, { name: 'Lucy', score: 76 }, { name: 'Jack', score: 88 }, ]; var groupByGrade = R.groupBy((student) => { let score = student.score; return score < 65 ? 'F' : score < 70 ? 'D' : score < 80 ? 'C' : score < 90 ? 'B' : 'A'; }); let grouped = groupByGrade(students); console.log('Student(s) having A grade:'); console.log(grouped['A']); console.log('Student(s) having B grade:'); console.log(grouped['B']); console.log('Student(s) having C grade:'); console.log(grouped['D']); console.log('Student(s) having D grade:'); console.log(grouped['D']); console.log('Student(s) having F grade:'); console.log(grouped['F']);
In the example, we group students by their score into grade sublists.
$ node grouping.js Student(s) having A grade: [ { name: 'Roman', score: 93 } ] Student(s) having B grade: [ { name: 'Adam', score: 84 }, { name: 'Jack', score: 88 } ] Student(s) having C grade: [ { name: 'Peter', score: 69 } ] Student(s) having D grade: [ { name: 'Peter', score: 69 } ] Student(s) having F grade: [ { name: 'Eddy', score: 58 }, { name: 'Jane', score: 56 } ]
This is the output.
Ramda reduce function
The reduce()
function aggregates list values into
a single value. It applies a function against an accumulator and each
element in the list (from left to right) to reduce it to a single value.
const R = require('ramda'); let nums = [2, 3, 4, 5, 6, 7]; let sum = R.reduce((x, y) => x+y, 0, nums); console.log(sum); let product = R.reduce((x, y) => x*y, 1, nums); console.log(product);
The example uses the reduce()
function to calculate a
sum and product of a list of integers.
let sum = R.reduce((x, y) => x+y, 0, nums);
In this line, we calculate a sum of values. The first parameter is the function that is applied on the values. The second is the accumulator, which is the starting value. The third is the list containing values.
let product = R.reduce((x, y) => x*y, 1, nums);
Here we calculate the product of the list values.
$ node reducefun.js 27 5040
This is the output.
The following example calculates the expression: 1*2 + 3*4 + 5*6
.
const R = require('ramda'); let nums = [1, 2, 3, 4, 5, 6]; let ret = R.reduce((acc, x) => acc + x[0] * x[1], 0, R.splitEvery(2, nums)); console.log(ret);
In the example, we split the list into pairs and apply a reduce operation on those pairs.
$ node reduce_fun2.js 44
This is the output.
Ramda where function
The where()
function allows to create complex queries
on objects.
const R = require('ramda'); const moment = require('moment'); const users = [ { name: 'John', city: 'London', born: '2001-04-01' }, { name: 'Lenny', city: 'New York', born: '1997-12-11' }, { name: 'Andrew', city: 'Boston', born: '1987-02-22' }, { name: 'Peter', city: 'Prague', born: '1936-03-24' }, { name: 'Anna', city: 'Bratislava', born: '1973-11-18' }, { name: 'Albert', city: 'Bratislava', born: '1940-12-11' }, { name: 'Adam', city: 'Trnava', born: '1983-12-01' }, { name: 'Robert', city: 'Bratislava', born: '1935-05-15' }, { name: 'Robert', city: 'Prague', born: '1998-03-14' } ]; let res1 = R.filter(R.where({ city: R.equals('Bratislava') }))(users); console.log(res1); let res2 = R.filter(R.where({ city: R.equals('Bratislava'), name: R.startsWith('A') }))(users); console.log(res2); let res3 = R.filter(R.where({ born: (dt) => getAge(dt) > 40}))(users); console.log(res3); function getAge(dt) { return moment.duration(moment() - moment(dt, 'YYYY-MM-DD', true)).years(); }
In the example, we create queries with where()
on a list
of users.
let res1 = R.filter(R.where({ city: R.equals('Bratislava') }))(users);
Here we find out all users living in Bratislava.
let res2 = R.filter(R.where({ city: R.equals('Bratislava'), name: R.startsWith('A') }))(users);
In this code we find out users that live in Bratislava and their name starts with 'A'.
let res3 = R.filter(R.where({ born: (dt) => getAge(dt) > 40}))(users);
Finally, we find out users that are older than 40.
function getAge(dt) { return moment.duration(moment() - moment(dt, 'YYYY-MM-DD', true)).years(); }
To compute the age from the supplied date of birth, we use the moment module.
$ node where_fun.js [ { name: 'Anna', city: 'Bratislava', born: '1973-11-18' }, { name: 'Albert', city: 'Bratislava', born: '1940-12-11' }, { name: 'Robert', city: 'Bratislava', born: '1935-05-15' } ] [ { name: 'Anna', city: 'Bratislava', born: '1973-11-18' }, { name: 'Albert', city: 'Bratislava', born: '1940-12-11' } ] [ { name: 'Peter', city: 'Prague', born: '1936-03-24' }, { name: 'Anna', city: 'Bratislava', born: '1973-11-18' }, { name: 'Albert', city: 'Bratislava', born: '1940-12-11' }, { name: 'Robert', city: 'Bratislava', born: '1935-05-15' } ]
This is the output.
In this tutorial, we have worked with the Ramda
library.
List all JavaScript tutorials.