Ebooks

Ramda tutorial

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 i 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
v9.11.2

We use Node version 9.11.2.

$ npm init

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.

add_sub.js
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.

flipfun.js
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.

calling.js
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.

applyfun.js
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.

currying.js
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.

head_tail.js
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.

lengthfun.js
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.

propfun.js
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.

plucking.js
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.

plucking2.js
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 contains function

The contains() function returns true if the specified value is in the list.

containsfun.js
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).

rangefun.js
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.

summation.js
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.

productfun.js
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.

sort_reverse.js
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.

Ramda sortBy function

The sortBy() function sort the list according to the supplied function.

sorting_objects.js
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.

finding.js
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.

finding2.js
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.

mapping.js
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).

filtering.js
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.

filtering2.js
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.

rejecting.js
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.

partitionfun.js
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.

grouping.js
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.

reducefun.js
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.

Ramda where function

The where() function allows to create complex queries on objects.

wherefun.js
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-18-11' },
  { 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 wherefun.js 
[ { name: 'Anna', city: 'Bratislava', born: '1973-18-11' },
  { name: 'Albert', city: 'Bratislava', born: '1940-12-11' },
  { name: 'Robert', city: 'Bratislava', born: '1935-05-15' } ]
[ { name: 'Anna', city: 'Bratislava', born: '1973-18-11' },
  { name: 'Albert', city: 'Bratislava', born: '1940-12-11' } ]
[ { name: 'Peter', city: 'Prague', born: '1936-03-24' },
  { 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.

You might also be interested in the following related tutorials: Lodash tutorial, JavaScript arrays, Moment.js tutorial. .