# Ramda function library reference tutorial

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

I found that this is a very important library that provides many useful methods, and every JavaScript programmer should master this tool.

You may ask, Underscore and Lodash have become so popular, why do you want to learn Ramda which seems to be the same?

The answer is that the parameter positions of the first two are wrong, and the processed data is placed in the first parameter.

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

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

Ramda’s data is always placed in the last parameter, the idea is ” function first, data last “.

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

Why is Underscore and Lodash wrong, but Ramda is right? This will be explained in detail in the next article . Today I will mainly introduce dozens of methods provided by Ramda. This is necessary to understand the content in the future.

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

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

``````
// 写法一
R.map(square, [4, 8])

// 写法二
R.map(square)([4, 8])
// 或者
var mapSquare = R.map(square);
mapSquare([4, 8]);
``````

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

Because of these two characteristics, Ramda has become the most ideal tool library for JavaScript functional programming. Today, I first introduce its API, and next time I will introduce how these methods can be used in actual combat. I guarantee that once you understand its calculation model, you will definitely agree that this is the correct calculation method.

All of the following examples, are available in the test environment online operation.

## contents

A comparison operation
two, math
three logic operation
four string
five functions
– 5.1 Synthesis Function
– currying 5.2
– 5.3 Functions performed
six array
– the array is determined characteristics 6.1
– 6.2 array taken and added
– 6.3 filter array
– single array operation 6.4
– 6.5 pairs of array operation
– 6.6 complex array of
seven, the object
– the object is determined characteristics 7.1
– 7.2 filter object
– the object taken 7.3
– 7.4 computation object
– the object compound 7.5

## One, comparison operation

``` gt ``` : Determine whether the first parameter is greater than the second parameter.

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

``` gte ``` : Determine whether the first parameter is greater than or equal to the second parameter.

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

``` lt ``` : Judge whether the first parameter is less than the second parameter.

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

``` lte ``` : Determine whether the first parameter is less than or equal to the second parameter.

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

``` equals ``` : Compare whether two values ​​are equal (support comparison of 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 ``` : Compare whether the operation result of two values ​​passed into the specified function is equal.

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

## 2. Mathematical operations

``` add ``` : Return the sum of two values.

``````
``````

``` subtract ``` : Returns the difference of the first parameter minus the second parameter.

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

``` multiply ``` : Returns the product of two values.

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

``` divide ``` : Returns the quotient of the first parameter divided by the second parameter.

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

## Three, logical operations

``` either ``` : Accept two functions as parameters, as long as one returns ``` true ``` , it returns ``` true ``` , otherwise it returns ``` false ``` . Equivalent to ``` || ``` operations.

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

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

``` both ``` : Accept two functions as parameters, only if they both return ``` true ``` , then return ``` true ``` , otherwise return ``` 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 ``` : Accept a function array as a parameter, only if they all return ``` true ``` , then return ``` true ``` , otherwise return ``` false ``` .

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

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

## Four, string

``` split ``` : Split the string into an array according to the specified delimiter.

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

``` test ``` : Determine whether a string matches a given regular expression.

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

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

``` match ``` : 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"
``````

## Five, function

### 5.1 Function composition

``` compose ``` : Combine multiple functions into one function and execute from right to left.

``````
``````

``` pipe ``` : Combine multiple functions into one function and execute 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 ``` : Accepts two parameters, the first parameter is a function, and the second parameter is a function array. The passed-in value is processed separately using the function contained in the second parameter, and then the result generated in the previous step is 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
// 相当于 28 除以 7

var toUpperCase = s => s.toUpperCase();
var toLowerCase = s => s.toLowerCase();
var strangeConcat = R.converge(R.concat, [toUpperCase, toLowerCase])
strangeConcat("Yodel")
// "YODELyodel"
// 相当于 R.concat('YODEL', 'yodel')
``````

### 5.2 Currying

``` curry ``` : Convert a multi-parameter function into a single-parameter form.

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

var g = f(3);
g(4) // 10
``````

``` partial ``` : Allow multi-parameter functions to accept an array and specify the leftmost part of the parameters.

``````
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 ``` : ``` partial ``` Similar, 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 ``` : Accepts a function ``` fn ``` and a function array ``` fnList ``` as parameters, and returns ``` fn ``` the curried version. The parameters of the new function are ``` fnList ``` processed by the corresponding members first , and then passed into and ``` fn ``` executed.

``````
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 ``` : Return a function that will cache the results of each run.

``````
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 ``` : Return a new function. If the original function returns ``` true ``` , the function returns ``` false ``` ; 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 ``` : When the parameter function is executed, only the first two parameters are passed in.

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

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

``` tap ``` : Pass a value into the specified function and return 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 ``` : Pass the values ​​of the corresponding positions of the two arrays into a function together as parameters.

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

``` apply ``` : Convert the array into a sequence of parameters and pass in the specified function.

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

``` applySpec ``` : Return a template function, which will pass parameters to the function execution in the template, and then fill the execution result into the template.

``````
var getMetrics = R.applySpec({
nested: { mul: R.multiply }
});

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

``` ascend ``` : Returns a comparison function in ascending order, mainly used for sorting.

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

``` descend ``` : Returns a comparison function in descending order, mainly used for sorting.

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

## Six, array

### 6.1 Feature judgment of array

``` contains ``` : If a member is included, return ``` true ``` .

``````
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 ``` : When all members meet the specified function, return ``` true ``` , otherwise return ``` false ```

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

``` any ``` : As long as one member meets the condition, return ``` true ``` .

``````
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 ``` : Return when no member meets the conditions ``` true ``` .

``````
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 Interception and addition of arrays

``` head ``` : Returns the first member of the array.

``````
``````

``` last ``` : Returns the last member of the array.

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

``` tail ``` : Return a new array composed 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 ``` : Return a new array composed 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 ``` : Retrieve the member at 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 ``` : Take 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 ``` : N members after removal.

``````
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 ``` : From the starting position (including) to the ending position (not including), a new array is truncated from 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 ``` : Remove ``` n ``` members after the start position .

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

``` insert ``` : Insert the given value at the specified position.

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

``` insertAll ``` : Insert 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 ``` : Insert a member at the head of the array

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

``` append ``` : Append a new member to the end of the array.

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

``` intersperse ``` : Insert a member representing the separation between the array members.

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

``` join ``` : Combine the arrays into a string, and insert a separator between the members.

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

### 6.3 Filtering of arrays

``` filter ``` : Filter out eligible members.

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

``` reject ``` : Filter out all members that do not meet the conditions.

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

``` takeWhile ``` : Once the conditions are met, the following members will be filtered.

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

``` dropWhile ``` : Once the conditions are not met, remove all the remaining members.

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

``` without ``` : Return members other than the specified value.

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

### 6.4 Single array operations

``` countBy ``` : After executing the specified function for each member, an object is returned, indicating how many members are included in the various execution results.

``````
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 ``` : At a given position, divide the original array into two parts.

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

``` splitEvery ``` : Divide 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 ``` : Divide the array into two parts with the first member satisfying the specified function as the boundary.

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

``` aperture ``` : Each member is divided into a group with a given number of members afterwards, and these groups form a new array.

``````
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 ``` : According to whether the specified function is satisfied, the members are partitioned.

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

``` indexOf ``` : The position of 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 position of 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 ``` : ``` map ``` Similar, the difference is that the traversal function can obtain two additional parameters: the index position and the original array.

``````
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, always returning 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 members of the array execute the specified function in turn, and the result of each operation will enter a cumulative variable.

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

``` reduceRight ``` : ``` reduce ``` Similar, the difference is that the array members are executed from left to right.

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

``` reduceWhile ``` : ``` reduce ``` Similar, the difference is that there is a judgment function, once the array member does not meet the conditions, it stops accumulating.

``````
var isOdd = (acc, x) => x % 2 === 1;
var xs = [1, 3, 5, 60, 777, 800];

var ys = [2, 4, 6];
``````

``` 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 sorting 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 member at the specified position.

``````
``````

``` ap ``` : The members of the array execute a set of functions separately and combine the results into a new array.

``````
// [2, 4, 6, 4, 5, 6]

``````

``` flatten ``` : Flatten the nested array.

``````
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 ``` : Compare the members of the array pair by pair according to the specified conditions in turn, and put all the members into the sub-array according to the result.

``````
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 operations

``` 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 the members at the specified positions of the two arrays together to generate a new array.

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

``` zipObj ``` : Use the members at the specified positions of the two arrays as the key name and key value, respectively, to generate a new object.

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

``` xprod ``` : Mix the members of the two arrays in pairs to generate a new array.

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

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

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

``` intersectionWith ``` : Return two members that have the same result after a certain operation.

``````
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 of the first array that are 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 the members that do not meet the conditions in the first array after the specified function is executed.

``````
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 composed of non-common 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 ``` : According to the specified conditions, return a new array composed of all the members of the two arrays whose operation results are not equal.

``````
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 members that meet the specified conditions.

``````
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 ``` : Returns the location of members that meet the specified conditions.

``````
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 conditions.

``````
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 conditions.

``````
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 out an attribute of an array member 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 attributes 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];
``````

``` transpose ``` : Combine the values ​​at the same position of 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 the array into one 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 the nested array into an object.

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

``` groupBy ``` : Group the members of the array according to the specified conditions.

``````
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}];
// {
//   'A': [{name: 'Dianne', score: 99}],
//   'B': [{name: 'Abby', score: 84}]
//   // ...,
//   'F': [{name: 'Eddy', score: 58}]
// }
``````

``` sortBy ``` : Sort according to a certain attribute of the member.

``````
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]
``````

## Seven, the object

### 7.1 Judgment of characteristics of objects

``` has ``` : Returns a boolean value indicating whether the object itself has this attribute.

``````
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 ``` : Returns 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 ``` : If the attribute is equal to the given value, return ``` true ``` .

``````
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 ``` : If the attribute is equal to the given value, return ``` true ``` .

``````
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 ``` : If all attributes meet the specified conditions, return ``` true ``` .

``````
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 specified attributes.

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

``` filter ``` : Return all attributes that meet the conditions

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

``` reject ``` : Return all attributes that do not meet the conditions

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

### 7.3 Interception of objects

``` dissoc ``` : Filter specified attributes.

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

``` assoc ``` : Add or rewrite an attribute.

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

``` partition ``` : According to whether the attribute value meets the given condition, the attribute is divided.

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

``` pick ``` : Return a new object composed of specified attributes

``````
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 ``` : ``` pick ``` Similar, but will include non-existent attributes.

``````
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 attributes that meet the conditions

``````
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 composed 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 object’s own and inherited property names.

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

``` values ``` : Returns an array of the property values ​​of the object’s own properties.

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

``` valuesIn ``` : Returns an array of the property values ​​of the object’s own and inherited properties.

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

``` invertObj ``` : Exchange the attribute value and attribute name. If multiple attributes have the same attribute value, only the last attribute is returned.

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

``` invert ``` : Exchange the attribute value and attribute name, and each attribute value corresponds to an array.

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

### 7.4 Operation of objects

``` prop ``` : Return the specified attributes of the object

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

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

``` map ``` : All properties of the object execute a function in turn.

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

``` mapObjIndexed ``` : ``` map ``` Similar, but will additionally pass in the attribute name 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 ``` : Each attribute executes the given function in turn, the parameters of the given function are the attribute value and the attribute name, and the original object is 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 are attributes 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 are attributes with the same name, they will be processed using the 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 whether the specified attributes of two objects are equal.

``````
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, and a new object is returned.

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

### 7.5 Compound Object

``` path ``` : Get 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 members whose values ​​of the specified path meet the conditions

``````
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 rewrite the value of the attribute 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}}}
``````

(over)