Login With Github

The Most Detailed Tutorial For Ramda Function Library

I came into contact with Ramda.js in the process of learning functional programming.

I find that it is a very important library which provides a lot of useful methods, and I believe this is a tool that every JavaScript programmer should master.

You might ask, now that Underscore and Lodash are so popular, why do we need to learn the similar Ramda?

The reason is that the parameters of the first two are not in the proper place, for they put the data to be processed in the first parameter.

var square = n => n * n;
_.map([4, 8], square) // [16, 64]

In the above code, the first parameter [4, 8] of _.map is the data to be processed, and the second parameter square is the operation to be performed by the data.

The data of Ramda is always placed in the last parameter, so it is "function first, data last".

var R = require('ramda');
R.map(square, [4, 8]) // [16, 64]

Why Underscore and Lodash are wrong while Ramda is right will be explained in detail in the next article. Today I mainly introduce dozens of methods provided by Ramda. This is necessary for understanding the content of the future.

In addition to the data being placed in the last parameter, Ramda has another feature: all the methods support currying.

In other words, all multi-parameter functions can be used as a single parameter by default.

// Writing one
R.map(square, [4, 8])

// Writing two
R.map(square)([4, 8])
// or
var mapSquare = R.map(square);
mapSquare([4, 8]);

In the above code, the first writing is a multi-parameter version, and the second writing is a single-parameter version after currying. Ramda supports both, and the second is recommended.

Thanks to these two features, Ramda becomes the most ideal tool library for JavaScript functional programming. I'll introduce its APIs  in this article, and how to use these methods for actual use will be introduced in another article. I promise that once you understand its computing model, you will definitely agree that this is the proper method for calculation.

All of the examples below can be run online on the test environment.

Introduction to the Ramda API

1. Comparison Operation

gt: It determines whether the first parameter is greater than the second parameter.

R.gt(2)(1) // true
R.gt('a')('z') // false

gte: It determines whether the first parameter is greater than or equal to the second parameter.

R.gte(2)(2) // true
R.gte('a')('z') // false

lt: It determines whether the first parameter is less than the second parameter.

R.lt(2)(1) // false
R.lt('a')('z') // true

lte: It determines whether the first parameter is less than or equal to the second parameter.

R.lte(2)(2) // true
R.lte('a')('z') // true

equals: It compares whether two values ​​are equal (It supports comparison for objects).

R.equals(1)(1) // true
R.equals(1)('1') // false
R.equals([1, 2, 3])([1, 2, 3]) // true

var a = {}; 
a.v = a;
var b = {}; 
b.v = b;
R.equals(a)(b)
// true

eqBy: It compares whether the operation results of passing two values to the specified function are equal.

R.eqBy(Math.abs, 5)(-5)
// true

2. Mathematical Operation

add: It returns the sum of two values.

R.add(7)(10) // 17

subtract: It returns the difference between the first parameter minus the second parameter.

R.subtract(10)(8) // 2

multiply: It returns the product of two values.

R.multiply(2)(5)  // 10

divide: It returns the quotient of the first parameter divided by the second parameter.

R.divide(71)(100) // 0.71

3. Logical Operation

either: It accepts two functions as parameters, and it returns true as long as one returns true, otherwise returns false. It's equivalent to || operation.

var gt10 = x => x > 10;
var even = x => x % 2 === 0;

var f = R.either(gt10, even);
f(101) // true
f(8) // true

both: It accepts two functions as parameters, and it returns true only if both return true, otherwise returns false, which is equivalent to && operation.

var gt10 = x => x > 10;
var even = x => x % 2 === 0;

var f = R.both(gt10, even);
f(15) // false
f(30) // true

allPass: It accepts a function array as a parameter, and it returns true only if they all return true, otherwise returns false.

var gt10 = x => x > 10;
var even = x => x % 2 === 0;

var isEvenAndGt10 = R.allPass([gt10, even]);
isEvenAndGt10(15) // false
isEvenAndGt10(30) // true

4. String

split: It splits the string into an array according to the specified separator.

R.split('.')('a.b.c.xyz.d')
// ['a', 'b', 'c', 'xyz', 'd']

test: It determines whether a string matches a given regular expression.

R.test(/^x/)('xyz')
// true

R.test(/^y/)('xyz')
// false

match: It returns the matching result of a string.

R.match(/([a-z]a)/g)('bananas')
// ['ba', 'na', 'na']

R.match(/a/)('b')
// []

R.match(/a/)(null)
// TypeError: null does not have a method named "match"

5. Function

5.1 Composite of functions

compose: It combines multiple functions into one function, executing from right to left.

R.compose(Math.abs, R.add(1), R.multiply(2))(-4) // 7

pipe: It combines multiple functions into one function, executing from left to right.

var negative = x => -1 * x;
var increaseOne = x => x + 1;

var f = R.pipe(Math.pow, negative, increaseOne);
f(3, 4) // -80 => -(3^4) + 1

converge: It accepts two parameters, the first is a function, and the second is an array of functions. The values passed in will be processed by the function contained in the second parameter separately, and then the results generated in the previous step will be processed with the first parameter.

var sumOfArr = arr => {
  var sum = 0;
  arr.forEach(i => sum += i);
  return sum;
};
var lengthOfArr = arr => arr.length;

var average = R.converge(R.divide, [sumOfArr, lengthOfArr])
average([1, 2, 3, 4, 5, 6, 7])
// 4
// It's equivalent to 28 divided by 7.

var toUpperCase = s => s.toUpperCase();
var toLowerCase = s => s.toLowerCase();
var strangeConcat = R.converge(R.concat, [toUpperCase, toLowerCase])
strangeConcat("Yodel")
// "YODELyodel"
// It's equivalent to  R.concat('YODEL', 'yodel').

5.2 Currying

curry: It converts a multi-parameter function into a form of a single-parameter.

var addFourNumbers = (a, b, c, d) => a + b + c + d;

var curriedAddFourNumbers = R.curry(addFourNumbers);
var f = curriedAddFourNumbers(1, 2);
var g = f(3);
g(4) // 10

partial: It allows a multiple-parameter function to accept an array specifying the leftmost part of the parameter.

var multiply2 = (a, b) => a * b;
var double = R.partial(multiply2, [2]);
double(2) // 4

var greet = (salutation, title, firstName, lastName) =>
  salutation + ', ' + title + ' ' + firstName + ' ' + lastName + '!';

var sayHello = R.partial(greet, ['Hello']);
var sayHelloToMs = R.partial(sayHello, ['Ms.']);
sayHelloToMs('Jane', 'Jones'); //=> 'Hello, Ms. Jane Jones!'

partialRight: It's similar to partial, but the parameter specified by the array is the rightmost parameter.

var greet = (salutation, title, firstName, lastName) =>
  salutation + ', ' + title + ' ' + firstName + ' ' + lastName + '!';

var greetMsJaneJones = R.partialRight(greet, ['Ms.', 'Jane', 'Jones']);
greetMsJaneJones('Hello') // 'Hello, Ms. Jane Jones!'

useWith: It accepts a function fn and a function array fnList as arguments, returning the curried version of fn. The parameters of the new function are processed by the corresponding fnList member respectively and then passed to fn.

var decreaseOne = x => x - 1;
var increaseOne = x => x + 1;

R.useWith(Math.pow, [decreaseOne, increaseOne])(3, 4) // 32
R.useWith(Math.pow, [decreaseOne, increaseOne])(3)(4) // 32

memoize: It returns a function and caches each operation result.

var productOfArr = arr => {
  var product = 1;
  arr.forEach(i => product *= i);
  return product;
};
var count = 0;
var factorial = R.memoize(n => {
  count += 1;
  return productOfArr(R.range(1, n + 1));
});
factorial(5) // 120
factorial(5) // 120
factorial(5) // 120
count // 1

complement: It returns a new function, and it returns false if the original function returns true; if the original function returns false, the function returns true.

var gt10 = x => x > 10;
var lte10 = R.complement(gt10);
gt10(7) // false
lte10(7) // true

5.3 Function execution

binary: It passes in only the first two parameters when executing the parameter function.

var takesThreeArgs = function(a, b, c) {
  return [a, b, c];
};

var takesTwoArgs = R.binary(takesThreeArgs);
takesTwoArgs(1, 2, 3) // [1, 2, undefined]

tap: It passes a value to the specified function and returns the value.

var sayX = x => console.log('x is ' + x);
R.tap(sayX)(100) // 100

R.pipe(
  R.assoc('a', 2),
  R.tap(console.log),
  R.assoc('a', 3)
)({a: 1})
// {a: 3}

zipWith: It passes the values ​​of the corresponding positions of the two arrays together as a parameter to a function.

var f = (x, y) => {
  // ...
};
R.zipWith(f, [1, 2, 3])(['a', 'b', 'c'])
// [f(1, 'a'), f(2, 'b'), f(3, 'c')]

apply: It converts the array into a sequence of parameters passing into the specified function.

var nums = [1, 2, 3, -99, 42, 6, 7];
R.apply(Math.max)(nums) // 42

applySpec: It returns a template function that passes the parameters to the function execution in the template and then populates the execution results into the template.

var getMetrics = R.applySpec({
  sum: R.add,
  nested: { mul: R.multiply }
});

getMetrics(2, 4) // { sum: 6, nested: { mul: 8 } }

ascend: It returns a comparison function of ascending order, mainly used for sorting.

var byAge = R.ascend(R.prop('age'));
var people = [
  // ...
];
var peopleByYoungestFirst = R.sort(byAge)(people);

descend: It returns a comparison function of descending order, mainly used for sorting.

var byAge = R.descend(R.prop('age'));
var people = [
  // ...
];
var peopleByOldestFirst = R.sort(byAge)(people);

6. Array

6.1 Feature judgment for arrays

contains: It returns true if a member is included.

R.contains(3)([1, 2, 3]) // true
R.contains(4)([1, 2, 3]) // false
R.contains({ name: 'Fred' })([{ name: 'Fred' }]) // true
R.contains([42])([[42]]) // true

all: It returns true if all members satisfy the specified function, otherwise returns false.

var equals3 = R.equals(3);
R.all(equals3)([3, 3, 3, 3]) // true
R.all(equals3)([3, 3, 1, 3]) // false

any: It returns true as long as one member satisfies the condition.

var lessThan0 = R.flip(R.lt)(0);
var lessThan2 = R.flip(R.lt)(2);
R.any(lessThan0)([1, 2]) // false
R.any(lessThan2)([1, 2]) // true

none: It returns true if none of the members satisfy the condition.

var isEven = n => n % 2 === 0;

R.none(isEven)([1, 3, 5, 7, 9, 11]) // true
R.none(isEven)([1, 3, 5, 7, 8, 11]) // false

6.2 Intercepting and adding to array

head: It returns the first member of the array.

R.head(['fi', 'fo', 'fum']) // 'fi'
R.head([])  // undefined
R.head('abc') // 'a'
R.head('') // ''

last: It returns the last member of the array.

R.last(['fi', 'fo', 'fum']) // 'fum'
R.last([]) // undefined
R.last('abc') // 'c'
R.last('') // ''

tail: It returns a new array of all members except the first member.

R.tail([1, 2, 3])  // [2, 3]
R.tail([1, 2])     // [2]
R.tail([1])        // []
R.tail([])         // []

R.tail('abc')  // 'bc'
R.tail('ab')   // 'b'
R.tail('a')    // ''
R.tail('')     // ''

init: It returns a new array of all members except the last member.

R.init([1, 2, 3])  // [1, 2]
R.init([1, 2])     // [1]
R.init([1])        // []
R.init([])         // []

R.init('abc')  // 'ab'
R.init('ab')   // 'a'
R.init('a')    // ''
R.init('')     // ''

nth: It takes out the member of the specified location.

var list = ['foo', 'bar', 'baz', 'quux'];
R.nth(1)(list) // 'bar'
R.nth(-1)(list) // 'quux'
R.nth(-99)(list) // undefined

R.nth(2)('abc') // 'c'
R.nth(3)('abc') // ''

take: It takes out the first n members.

R.take(1)(['foo', 'bar', 'baz']) // ['foo']
R.take(2)(['foo', 'bar', 'baz']) // ['foo', 'bar']
R.take(3)(['foo', 'bar', 'baz']) // ['foo', 'bar', 'baz']
R.take(4)(['foo', 'bar', 'baz']) // ['foo', 'bar', 'baz']
R.take(3)('ramda')               // 'ram'

takeLast: It takes out the last n members.

R.takeLast(1)(['foo', 'bar', 'baz']) // ['baz']
R.takeLast(2)(['foo', 'bar', 'baz']) // ['bar', 'baz']
R.takeLast(3)(['foo', 'bar', 'baz']) // ['foo', 'bar', 'baz']
R.takeLast(4)(['foo', 'bar', 'baz']) // ['foo', 'bar', 'baz']
R.takeLast(3)('ramda')               // 'mda'

slice: It takes out a new array which is from the start position (included) to the end position (not included) in the original array.

R.slice(1, 3)(['a', 'b', 'c', 'd']) // ['b', 'c']
R.slice(1, Infinity)(['a', 'b', 'c', 'd']) // ['b', 'c', 'd']
R.slice(0, -1)(['a', 'b', 'c', 'd']) // ['a', 'b', 'c']
R.slice(-3, -1)(['a', 'b', 'c', 'd']) // ['b', 'c']
R.slice(0, 3)('ramda') // 'ram'

remove: It removes n members from the start position.

R.remove(2, 3)([1,2,3,4,5,6,7,8]) // [1,2,6,7,8]

insert: It inserts the given value at the specified position.

R.insert(2, 'x')([1,2,3,4]) // [1,2,'x',3,4]

insertAll: It inserts all members of another array at the specified position.

R.insertAll(2,['x','y','z'])([1,2,3,4]) // [1,2,'x','y','z',3,4]

prepend: It inserts a member at the head of the array.

R.prepend('fee')(['fi', 'fo', 'fum'])
// ['fee', 'fi', 'fo', 'fum']

prepend: It appends a new member to the tail of the array.

R.append('tests')(['write', 'more']) // ['write', 'more', 'tests']
R.append('tests')([]) // ['tests']
R.append(['tests'])(['write', 'more']) // ['write', 'more', ['tests']]

intersperse: It inserts a member that represents a separator between array members.

R.intersperse('n')(['ba', 'a', 'a'])
// ['ba', 'n', 'a', 'n', 'a']

join: It combines the array into a string and inserts a separator between the members.

R.join('|')([1, 2, 3]) // '1|2|3'

6.3 Filtering arrays

filter: It filters out the eligible members.

var isEven = n => n % 2 === 0;
R.filter(isEven)([1, 2, 3, 4]) // [2, 4]

reject: It filters out all the members that do not meet the condition.

var isOdd = (n) => n % 2 === 1;
R.reject(isOdd)([1, 2, 3, 4]) // [2, 4]

takeWhile: Once the condition is met, the members followed will be filtered.

var isNotFour = x => x !== 4;
R.takeWhile(isNotFour)([1, 2, 3, 4, 3, 2, 1]) // [1, 2, 3]

dropWhile: Once the condition is not met, all the remaining members will be taken out.

var lteTwo = x => x <= 2;
R.dropWhile(lteTwo)([1, 2, 3, 4, 3, 2, 1])
// [3, 4, 3, 2, 1]

without: It returns the members other than the specified values.

R.without([1, 2])([1, 2, 1, 3, 4])
// [3, 4]

6.4 Single-array operation

countBy:After executing the specified function for each member, it returns an object indicating how many members are included in each execution result.

var numbers = [1.0, 1.1, 1.2, 2.0, 3.0, 2.2];
R.countBy(Math.floor)(numbers)  // {'1': 3, '2': 2, '3': 1}

var letters = ['a', 'b', 'A', 'a', 'B', 'c'];
R.countBy(R.toLower)(letters)  // {'a': 3, 'b': 2, 'c': 1}

splitAt: It splits the original array into two parts at a given position.

R.splitAt(1)([1, 2, 3]) // [[1], [2, 3]]
R.splitAt(5)('hello world') // ['hello', ' world']
R.splitAt(-1)('foobar') // ['fooba', 'r']

splitEvery: It splits the original array into multiple parts according to the specified number.

R.splitEvery(3)([1, 2, 3, 4, 5, 6, 7])
// [[1, 2, 3], [4, 5, 6], [7]]

R.splitEvery(3)('foobarbaz')
// ['foo', 'bar', 'baz']

splitWhen: It splits the array into two parts, bounded by the first member that satisfies the specified function.

R.splitWhen(R.equals(2))([1, 2, 3, 1, 2, 3])
// [[1], [2, 3, 1, 2, 3]]

aperture: Each member is grouped with a given number of members to form new arrays.

R.aperture(3)([1, 2, 3, 4, 5, 6, 7])
// [[1, 2, 3], [2, 3, 4], [3, 4, 5], [4, 5, 6], [5, 6, 7]]

partition: Partition the members based on whether the member satisfy a specified function or not.

R.partition(R.contains('s'))(['sss', 'ttt', 'foo', 'bars'])
// => [ [ 'sss', 'bars' ],  [ 'ttt', 'foo' ] ]

indexOf: The first occurrence of a value in the array.

R.indexOf(3)([1,2,3,4]) // 2
R.indexOf(10)([1,2,3,4]) // -1

lastIndexOf: The last occurrence of a value in the array.

R.lastIndexOf(3)([-1,3,3,0,1,2,3,4]) // 6
R.lastIndexOf(10)([1,2,3,4]) // -1

map: Each member of the array executes a function in turn.

var double = x => x * 2;
R.map(double)([1, 2, 3]) // [2, 4, 6]

mapIndexed: It's similar to map, but the difference is that the traversal function can get two additional parameters: the index position and the original array.

var mapIndexed = R.addIndex(R.map);
mapIndexed(
  (val, idx) => idx + '-' + val, ['f', 'o', 'o', 'b', 'a', 'r']
)
// ['0-f', '1-o', '2-o', '3-b', '4-a', '5-r']

forEach: Each member of the array executes a function in turn, and it will always return to the original array.

var printXPlusFive = x => console.log(x + 5);
R.forEach(printXPlusFive, [1, 2, 3]) // [1, 2, 3]
// logs 6
// logs 7
// logs 8

reduce: The array member executes the specified function in turn, and each operation result will be entered into a cumulative variable.

var mySubtract = function (a, b) {
  return a - b;
};
R.reduce(mySubtract, 0)([1, 2, 3, 4]) // -10

reduceRight: It's similar to reduce, and the difference is that the array members are executed from left to right.

R.reduceRight(R.subtract, 0)([1, 2, 3, 4]) // -2

reduceWhile: It's similar to reduce, and the difference is that there is a judgment function used to stop accumulating once the array members do not meet the condition.

var isOdd = (acc, x) => x % 2 === 1;
var xs = [1, 3, 5, 60, 777, 800];
R.reduceWhile(isOdd, R.add, 0)(xs) // 9

var ys = [2, 4, 6];
R.reduceWhile(isOdd, R.add, 111)(ys) // 111

sort: Sort the array according to the given function.

var diff = function(a, b) { return a - b; };
R.sort(diff)([4,2,7,5])
// [2, 4, 5, 7]

sortWith: Perform multiple-sort according to a given set of functions.

var alice = {
  name: 'alice',
  age: 40
};
var bob = {
  name: 'bob',
  age: 30
};
var clara = {
  name: 'clara',
  age: 40
};
var people = [clara, bob, alice];
var ageNameSort = R.sortWith([
  R.descend(R.prop('age')),
  R.ascend(R.prop('name'))
]);
ageNameSort(people); //=> [alice, clara, bob]

adjust: Execute the given function on the members of the specified positions.

R.adjust(R.add(10), 1)([1, 2, 3]) // [1, 12, 3]
R.adjust(R.add(10),1)([1, 2, 3]) // [1, 12, 3]

ap: Array members execute a set of functions respectively, and synthesize the results into a new array.

R.ap([R.multiply(2), R.add(3)])([1,2,3])
// [2, 4, 6, 4, 5, 6]

R.ap([R.concat('tasty '), R.toUpper])(['pizza', 'salad'])
// ["tasty pizza", "tasty salad", "PIZZA", "SALAD"]

flatten: Flatten nested arrays.

R.flatten([1, 2, [3, 4], 5, [6, [7, 8, [9, [10, 11], 12]]]])
// [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]

groupBy: Pairwise compare the array members one by one according to the specified conditions, and put all members into the sub-array according to their results.

R.groupWith(R.equals)([0, 1, 1, 2, 3, 5, 8, 13, 21])
// [[0], [1, 1], [2], [3], [5], [8], [13], [21]]

R.groupWith((a, b) => a % 2 === b % 2)([0, 1, 1, 2, 3, 5, 8, 13, 21])
// [[0], [1, 1], [2], [3, 5], [8], [13, 21]]

R.groupWith(R.eqBy(isVowel), 'aestiou')
//=> ['ae', 'st', 'iou']

6.5 Double-array operation

concat: Combine two arrays into one array.

R.concat('ABC')('DEF') // 'ABCDEF'
R.concat([4, 5, 6])([1, 2, 3]) // [4, 5, 6, 1, 2, 3]
R.concat([])([]) // []

zip: Put together the members of the specified positions of the two arrays to generate a new array.

R.zip([1, 2, 3])(['a', 'b', 'c'])
// [[1, 'a'], [2, 'b'], [3, 'c']]

zipObj: Generate a new object by using the members of the specified positions of the two arrays as key names and key values.

R.zipObj(['a', 'b', 'c'])([1, 2, 3])
// {a: 1, b: 2, c: 3}

xprod: Pairwise mix the members of two arrays to generate a new array.

R.xprod([1, 2])(['a', 'b'])
// [[1, 'a'], [1, 'b'], [2, 'a'], [2, 'b']]

intersection: Return a new array consisting of the same members of two arrays.

R.intersection([1,2,3,4], [7,6,5,4,3]) // [4, 3]

intersectionWith: Return the pairs of members, which have the same result after being executed some operation on.

var buffaloSpringfield = [
  {id: 824, name: 'Richie Furay'},
  {id: 956, name: 'Dewey Martin'},
  {id: 313, name: 'Bruce Palmer'},
  {id: 456, name: 'Stephen Stills'},
  {id: 177, name: 'Neil Young'}
];
var csny = [
  {id: 204, name: 'David Crosby'},
  {id: 456, name: 'Stephen Stills'},
  {id: 539, name: 'Graham Nash'},
  {id: 177, name: 'Neil Young'}
];

R.intersectionWith(R.eqBy(R.prop('id')),buffaloSpringfield)(csny)
// [{id: 456, name: 'Stephen Stills'}, {id: 177, name: 'Neil Young'}]

difference: Return the members which are in the first array but not contained in the second array.

R.difference([1,2,3,4])([7,6,5,4,3]) // [1,2]
R.difference([7,6,5,4,3])([1,2,3,4]) // [7,6,5]
R.difference([{a: 1}, {b: 2}])([{a: 1}, {c: 3}]) // [{b: 2}]

differenceWith: Return all members of the first array that do not meet the criteria, after executing the specified function.

var cmp = (x, y) => x.a === y.a;
var l1 = [{a: 1}, {a: 2}, {a: 3}];
var l2 = [{a: 3}, {a: 4}];
R.differenceWith(cmp, l1)(l2) // [{a: 1}, {a: 2}]

symmetricDifference: Return a new array consisting of non-shared members of two arrays.

R.symmetricDifference([1,2,3,4])([7,6,5,4,3]) // [1,2,7,6,5]
R.symmetricDifference([7,6,5,4,3])([1,2,3,4]) // [7,6,5,1,2]

symmetricDifferenceWith: Return a new array consisting of all the members which are from two arrays but have unequal operation results, according to the specified condition.

var eqA = R.eqBy(R.prop('a'));
var l1 = [{a: 1}, {a: 2}, {a: 3}, {a: 4}];
var l2 = [{a: 3}, {a: 4}, {a: 5}, {a: 6}];
R.symmetricDifferenceWith(eqA, l1, l2) // [{a: 1}, {a: 2}, {a: 5}, {a: 6}]

6.6 Composite array

find: Return a member that meets the specified criteria.

var xs = [{a: 1}, {a: 2}, {a: 3}];
R.find(R.propEq('a', 2))(xs) // {a: 2}
R.find(R.propEq('a', 4))(xs) // undefined

findIndex: Return the position of the member that meets the specified criteria.

var xs = [{a: 1}, {a: 2}, {a: 3}];
R.findIndex(R.propEq('a', 2))(xs) // 1
R.findIndex(R.propEq('a', 4))(xs) // -1

findLast: Return the last member that meets the specified criteria.

var xs = [{a: 1, b: 0}, {a:1, b: 1}];
R.findLast(R.propEq('a', 1))(xs) // {a: 1, b: 1}
R.findLast(R.propEq('a', 4))(xs) // undefined

findLastIndex: Return the position of the last member that meets the specified criteria.

var xs = [{a: 1, b: 0}, {a:1, b: 1}];
R.findLastIndex(R.propEq('a', 1))(xs) // 1
R.findLastIndex(R.propEq('a', 4))(xs) // -1

pluck: Take a property of array members out to form a new array.

R.pluck('a')([{a: 1}, {a: 2}]) // [1, 2]
R.pluck(0)([[1, 2], [3, 4]])   // [1, 3]

project: Take out multiple properties of array members to form a new array.

var abby = {name: 'Abby', age: 7, hair: 'blond', grade: 2};
var fred = {name: 'Fred', age: 12, hair: 'brown', grade: 7};
var kids = [abby, fred];
R.project(['name', 'grade'])(kids)
// [{name: 'Abby', grade: 2}, {name: 'Fred', grade: 7}]

transpose: Combine the values of the same position for each member into a new array.

R.transpose([[1, 'a'], [2, 'b'], [3, 'c']])
// [[1, 2, 3], ['a', 'b', 'c']]

R.transpose([[1, 2, 3], ['a', 'b', 'c']])
// [[1, 'a'], [2, 'b'], [3, 'c']]

R.transpose([[10, 11], [20], [], [30, 31, 32]])
// [[10, 20, 30], [11, 31], [32]]

mergeAll: Combine the members of an array into an object.

R.mergeAll([{foo:1},{bar:2},{baz:3}])
// {foo:1,bar:2,baz:3}

R.mergeAll([{foo:1},{foo:2},{bar:2}])
// {foo:2, bar:2}

fromPairs: Convert a nested array to an object.

R.fromPairs([['a', 1], ['b', 2], ['c', 3]])
// {a: 1, b: 2, c: 3}

groupBy: Group array members according to specified conditions.

var byGrade = R.groupBy(function(student) {
  var score = student.score;
  return score < 65 ? 'F' :
         score < 70 ? 'D' :
         score < 80 ? 'C' :
         score < 90 ? 'B' : 'A';
});
var students = [{name: 'Abby', score: 84},
                {name: 'Eddy', score: 58},
                // ...
                {name: 'Jack', score: 69}];
byGrade(students);
// {
//   'A': [{name: 'Dianne', score: 99}],
//   'B': [{name: 'Abby', score: 84}]
//   // ...,
//   'F': [{name: 'Eddy', score: 58}]
// }

sortBy: Sort array members according to a property.

var sortByFirstItem = R.sortBy(R.prop(0));
sortByFirstItem([[-1, 1], [-2, 2], [-3, 3]])
// [[-3, 3], [-2, 2], [-1, 1]]

var sortByNameCaseInsensitive = R.sortBy(
  R.compose(R.toLower, R.prop('name'))
);
var alice = {name: 'ALICE', age: 101};
var bob = {name: 'Bob', age: -10};
var clara = {name: 'clara', age: 314.159};
var people = [clara, bob, alice];
sortByNameCaseInsensitive(people)
// [alice, bob, clara]

7. Object

7.1 Feature judgment to objects

has: Return a Boolean value indicating whether the object itself has the property.

var hasName = R.has('name')
hasName({name: 'alice'})   //=> true
hasName({name: 'bob'})     //=> true
hasName({})                //=> false

var point = {x: 0, y: 0};
var pointHas = R.has(R.__, point);
pointHas('x')  // true
pointHas('y')  // true
pointHas('z')  // false

hasIn: Return a Boolean value indicating whether the object itself or the prototype chain has a certain property.

function Rectangle(width, height) {
  this.width = width;
  this.height = height;
}
Rectangle.prototype.area = function() {
  return this.width * this.height;
};

var square = new Rectangle(2, 2);
R.hasIn('width')(square)  // true
R.hasIn('area')(square)  // true

propEq: Return true if the property is equal to the given value.

var abby = {name: 'Abby', age: 7, hair: 'blond'};
var fred = {name: 'Fred', age: 12, hair: 'brown'};
var rusty = {name: 'Rusty', age: 10, hair: 'brown'};
var alois = {name: 'Alois', age: 15, disposition: 'surly'};
var kids = [abby, fred, rusty, alois];
var hasBrownHair = R.propEq('hair', 'brown');
R.filter(hasBrownHair)(kids) // [fred, rusty]

whereEq: Return true if the property is equal to the given value.

var pred = R.whereEq({a: 1, b: 2});

pred({a: 1})              // false
pred({a: 1, b: 2})        // true
pred({a: 1, b: 2, c: 3})  // true
pred({a: 1, b: 1})        // false

where: Return true if each property meets the specified criteria.

var pred = R.where({
  a: R.equals('foo'),
  b: R.complement(R.equals('bar')),
  x: R.gt(__, 10),
  y: R.lt(__, 20)
});

pred({a: 'foo', b: 'xxx', x: 11, y: 19}) // true
pred({a: 'xxx', b: 'xxx', x: 11, y: 19}) // false
pred({a: 'foo', b: 'bar', x: 11, y: 19}) // false
pred({a: 'foo', b: 'xxx', x: 10, y: 19}) // false
pred({a: 'foo', b: 'xxx', x: 11, y: 20}) // false

7.2 Filtering of objects

omit: Filter the specified properties.

R.omit(['a', 'd'])({a: 1, b: 2, c: 3, d: 4})
// {b: 2, c: 3}

filter: Return all the properties that satisfy the condition.

var isEven = n => n % 2 === 0;
R.filter(isEven)({a: 1, b: 2, c: 3, d: 4}) // {b: 2, d: 4}

reject: Return all the properties that do not meet the condition.

var isOdd = (n) => n % 2 === 1;
R.reject(isOdd)({a: 1, b: 2, c: 3, d: 4})
// {b: 2, d: 4}

7.3 Intercepting objects

dissoc: Filter the specified properties.

R.dissoc('b')({a: 1, b: 2, c: 3})
// {a: 1, c: 3}

assoc: Add or rewrite a certain property.

R.assoc('c', 3)({a: 1, b: 2})
// {a: 1, b: 2, c: 3}

partition: Partition the properties based on whether the property value satisfies the given condition or not.

R.partition(R.contains('s'))({ a: 'sss', b: 'ttt', foo: 'bars' })
// [ { a: 'sss', foo: 'bars' }, { b: 'ttt' }  ]

pick: Return a new object consisting of the specified properties.

R.pick(['a', 'd'])({a: 1, b: 2, c: 3, d: 4})
// {a: 1, d: 4}

R.pick(['a', 'e', 'f'])({a: 1, b: 2, c: 3, d: 4})
// {a: 1}

pickAll: It's similar to pick, but the properties that don't exist can be included in the new object.

R.pickAll(['a', 'd'])({a: 1, b: 2, c: 3, d: 4})
// {a: 1, d: 4}

R.pickAll(['a', 'e', 'f'])({a: 1, b: 2, c: 3, d: 4})
// {a: 1, e: undefined, f: undefined}

pickBy: Return the properties that satisfy the condition.

var isUpperCase = (val, key) => key.toUpperCase() === key;
R.pickBy(isUpperCase)({a: 1, b: 2, A: 3, B: 4})
// {A: 3, B: 4}

keys: Return a new array consisting of the property names of the object's own properties.

R.keys({a: 1, b: 2, c: 3}) // ['a', 'b', 'c']

keysIn: Return a new array consisting of the property names of the object's own properties and the object inherited properties.

var F = function() { this.x = 'X'; };
F.prototype.y = 'Y';
var f = new F();
R.keysIn(f) // ['x', 'y']

values: Return an array consisting of the property values ​​of the properties of the object itself.

R.values({a: 1, b: 2, c: 3}); //=> [1, 2, 3]

valuesIn: Return an array consisting of the property values ​​of the object's own properties and the object inherited properties.

var F = function() { this.x = 'X'; };
F.prototype.y = 'Y';
var f = new F();
R.valuesIn(f) // ['X', 'Y']

invertObj: Swap the property values ​​and property names. If the property values ​​of multiple properties are the same, only the last property is returned.

var raceResultsByFirstName = {
  first: 'alice',
  second: 'jake',
  third: 'alice',
};
R.invertObj(raceResultsByFirstName)
// {"alice": "third", "jake": "second"}

invert: Swap the property value and the property name. Each property value corresponds to an array.

var raceResultsByFirstName = {
  first: 'alice',
  second: 'jake',
  third: 'alice',
};
R.invert(raceResultsByFirstName)
// { 'alice': ['first', 'third'], 'jake':['second'] }

7.4 Operation for objects

prop: Return the specified property of the object.

R.prop('x')({x: 100})
// 100

R.prop('x')({})
// undefined

map: Execute a function in turn on all properties of an object.

var double = x => x * 2;
R.map(double)({x: 1, y: 2, z: 3})
// {x: 2, y: 4, z: 6}

mapObjIndexed: It's similar to map, but it will also pass in property names and the entire object.

var values = { x: 1, y: 2, z: 3 };
var prependKeyAndDouble = (num, key, obj) => key + (num * 2);

R.mapObjIndexed(prependKeyAndDouble)(values)
// { x: 'x2', y: 'y4', z: 'z6' }

forEachObjIndexed: Execute a given function in turn on each property. The parameters of the given function are the property value and the property name respectively, and the original object will be returned.

var printKeyConcatValue = (value, key) => console.log(key + ':' + value);
R.forEachObjIndexed(printKeyConcatValue)({x: 1, y: 2}) // {x: 1, y: 2}
// logs x:1
// logs y:2

merge: Merge two objects. If there is a property with the same name, the latter value will overwrite the previous value.

R.merge({ 'name': 'fred', 'age': 10 })({ 'age': 40 })
// { 'name': 'fred', 'age': 40 }

var resetToDefault = R.merge(R.__, {x: 0});
resetToDefault({x: 5, y: 2}) // {x: 0, y: 2}

mergeWith: Merge two objects. If there is a property with the same name, it will be processed using a specified function.

R.mergeWith(
  R.concat,
  { a: true, values: [10, 20] },
  { b: true, values: [15, 35] }
);
// { a: true, b: true, values: [10, 20, 15, 35] }

eqProps: Compare the specified properties of two objects for equality.

var o1 = { a: 1, b: 2, c: 3, d: 4 };
var o2 = { a: 10, b: 20, c: 3, d: 40 };
R.eqProps('a', o1)(o2) // false
R.eqProps('c', o1)(o2) // true

R.evolve: The properties of the object are processed by a set of functions respectively to return a new object.

var tomato  = {
  firstName: '  Tomato ',
  data: {elapsed: 100, remaining: 1400},
  id: 123
};
var transformations = {
  firstName: R.trim,
  lastName: R.trim, // 不会被调用
  data: {elapsed: R.add(1), remaining: R.add(-1)}
};
R.evolve(transformations)(tomato)
// {
//   firstName: 'Tomato',
//   data: {elapsed: 101, remaining: 1399},
//   id: 123
// }

7.5 composite object

path: Take out the value of the specified path in the array.

R.path(['a', 'b'], {a: {b: 2}}) // 2
R.path(['a', 'b'], {c: {b: 2}}) // undefined

pathEq: Return the member of the specified path whose value meets the criteria.

var user1 = { address: { zipCode: 90210 } };
var user2 = { address: { zipCode: 55555 } };
var user3 = { name: 'Bob' };
var users = [ user1, user2, user3 ];
var isFamous = R.pathEq(['address', 'zipCode'], 90210);
R.filter(isFamous)(users) // [ user1 ]

assocPath: Add or override the value of the property of the specified path.

R.assocPath(['a', 'b', 'c'], 42)({a: {b: {c: 0}}})
// {a: {b: {c: 42}}}

R.assocPath(['a', 'b', 'c'], 42)({a: 5})
// {a: {b: {c: 42}}}

1 Comment

temp

Thanks for sharing this, it's super helpful