1
0
Fork 0
arangodb/js/node/node_modules/ramda/ramda.js

5662 lines
183 KiB
JavaScript

// ramda.js
// https://github.com/ramda/ramda
// (c) 2013-2014 Scott Sauyet and Michael Hurley
// Ramda may be freely distributed under the MIT license.
// Ramda
// -----
// A practical functional library for Javascript programmers. Ramda is a collection of tools to make it easier to
// use Javascript as a functional programming language. (The name is just a silly play on `lambda`.)
// Basic Setup
// -----------
// Uses a technique from the [Universal Module Definition][umd] to wrap this up for use in Node.js or in the browser,
// with or without an AMD-style loader.
//
// [umd]: https://github.com/umdjs/umd/blob/master/returnExports.js
(function(factory) {
if (typeof exports === 'object') {
module.exports = factory(this);
} else if (typeof define === 'function' && define.amd) {
define(factory);
} else {
this.R = this.ramda = factory(this);
}
}(function() {
'use strict';
// This object is what is actually returned, with all the exposed functions attached as properties.
/**
* A practical functional library for Javascript programmers.
*
* @namespace R
*/
var R = {version: '0.7.2'};
// Internal Functions and Properties
// ---------------------------------
/**
* Creates an exception about calling a function with no arguments.
*
* @private
* @category Internal
* @return {TypeError} A no arguments exception.
*/
function noArgsException() {
return new TypeError('Function called with no arguments');
}
/**
* An optimized, private array `slice` implementation.
*
* @private
* @category Internal
* @param {Arguments|Array} args The array or arguments object to consider.
* @param {number} [from=0] The array index to slice from, inclusive.
* @param {number} [to=args.length] The array index to slice to, exclusive.
* @return {Array} A new, sliced array.
* @example
*
* _slice([1, 2, 3, 4, 5], 1, 3); //=> [2, 3]
*
* var firstThreeArgs = function(a, b, c, d) {
* return _slice(arguments, 0, 3);
* };
* firstThreeArgs(1, 2, 3, 4); //=> [1, 2, 3]
*/
function _slice(args, from, to) {
switch (arguments.length) {
case 0: throw noArgsException();
case 1: return _slice(args, 0, args.length);
case 2: return _slice(args, from, args.length);
default:
var length = to - from, list = new Array(length), idx = -1;
while (++idx < length) {
list[idx] = args[from + idx];
}
return list;
}
}
/**
* Private `concat` function to merge two array-like objects.
*
* @private
* @category Internal
* @param {Array|Arguments} [set1=[]] An array-like object.
* @param {Array|Arguments} [set2=[]] An array-like object.
* @return {Array} A new, merged array.
* @example
*
* concat([4, 5, 6], [1, 2, 3]); //=> [4, 5, 6, 1, 2, 3]
*/
var concat = function _concat(set1, set2) {
set1 = set1 || [];
set2 = set2 || [];
var length1 = set1.length,
length2 = set2.length,
result = new Array(length1 + length2);
for (var idx = 0; idx < length1; idx++) {
result[idx] = set1[idx];
}
for (idx = 0; idx < length2; idx++) {
result[idx + length1] = set2[idx];
}
return result;
};
// Private reference to toString function.
var toString = Object.prototype.toString;
/**
* Tests whether or not an object is an array.
*
* @private
* @category Internal
* @param {*} val The object to test.
* @return {boolean} `true` if `val` is an array, `false` otherwise.
* @example
*
* isArray([]); //=> true
* isArray(true); //=> false
* isArray({}); //=> false
*/
var isArray = Array.isArray || function _isArray(val) {
return val && val.length >= 0 && toString.call(val) === '[object Array]';
};
/**
* Tests whether or not an object is similar to an array.
*
* @func
* @memberOf R
* @category Type
* @category List
* @param {*} x The object to test.
* @return {boolean} `true` if `x` has a numeric length property and extreme indices defined; `false` otherwise.
* @example
*
* R.isArrayLike([]); //=> true
* R.isArrayLike(true); //=> false
* R.isArrayLike({}); //=> false
* R.isArrayLike({length: 10}); //=> false
* R.isArrayLike({0: 'zero', 9: 'nine', length: 10}); //=> true
*/
R.isArrayLike = function isArrayLike(x) {
if (isArray(x)) { return true; }
if (!x) { return false; }
if (typeof x !== 'object') { return false; }
if (x instanceof String) { return false; }
if (x.nodeType === 1) { return !!x.length; }
if (x.length === 0) { return true; }
if (x.length > 0) {
return x.hasOwnProperty(0) && x.hasOwnProperty(x.length - 1);
}
return false;
};
/**
* Optimized internal two-arity curry function.
*
* @private
* @category Function
* @param {Function} fn The function to curry.
* @return {Function} curried function
* @example
*
* var addTwo = function(a, b) {
* return a + b;
* };
*
* var curriedAddTwo = curry2(addTwo);
*/
function curry2(fn) {
return function(a, b) {
switch (arguments.length) {
case 0:
throw noArgsException();
case 1:
return function(b) {
return fn(a, b);
};
default:
return fn(a, b);
}
};
}
/**
* Optimized internal three-arity curry function.
*
* @private
* @category Function
* @param {Function} fn The function to curry.
* @return {Function} curried function
* @example
*
* var addThree = function(a, b, c) {
* return a + b + c;
* };
*
* var curriedAddThree = curry3(addThree);
*/
function curry3(fn) {
return function(a, b, c) {
switch (arguments.length) {
case 0:
throw noArgsException();
case 1:
return curry2(function(b, c) {
return fn(a, b, c);
});
case 2:
return function(c) {
return fn(a, b, c);
};
default:
return fn(a, b, c);
}
};
}
var __; // This is intentionally left `undefined`.
try {
Object.defineProperty(R, '__', {writable: false, value: __});
} catch (e) {
R.__ = __;
}
/**
* Uses a placeholder to convert a binary function into something like an infix operation.
* When called with an `undefined` placeholder (e.g. `R.__`) the second argument is applied to the
* second position, and it returns a function waiting for its first argument.
* This can allow for more natural processing of functions which are really binary operators.
*
* @func
* @memberOf R
* @category Function
* @param {function} fn The binary operation to adjust
* @return {function} A new function that acts somewhat like an infix operator.
* @example
*
* var div = R.op(function (a, b) {
* return a / b;
* });
*
* div(6, 3); //=> 2
* div(6)(3); //=> 2
* div(__, 3)(6); //=> 2 // note: `__` here is just an `undefined` value. You could use `void 0` instead
* div(__)(3, 6); //=> 2
* div(__)(3)(6); //=> 2
*/
var op = R.op = function op(fn) {
var length = fn.length;
if (length !== 2) {throw new Error('Expected binary function.');}
return function _op(a, b) {
switch (arguments.length) {
case 0: throw noArgsException();
case 1:
if (a === __) {
return R.binary(R.flip(_op));
}
return R.unary(R.lPartial(fn, a));
default:
if (a === __) {
return R.unary(R.rPartial(fn, b));
}
return fn(a, b);
}
};
};
/**
* Creates a new version of `fn` with given arity that, when invoked,
* will return either:
* - A new function ready to accept one or more of `fn`'s remaining arguments, if all of
* `fn`'s expected arguments have not yet been provided
* - `fn`'s result if all of its expected arguments have been provided
*
* This function is useful in place of `curry`, when the arity of the
* function to curry cannot be determined from its signature, e.g. if it's
* a variadic function.
*
* @func
* @memberOf R
* @category core
* @category Function
* @sig Number -> (* -> a) -> (* -> a)
* @param {number} fnArity The arity for the returned function.
* @param {Function} fn The function to curry.
* @return {Function} A new, curried function.
* @see R.curry
* @example
*
* var addFourNumbers = function() {
* return R.sum([].slice.call(arguments, 0, 4));
* };
*
* var curriedAddFourNumbers = R.curryN(4, addFourNumbers);
* var f = curriedAddFourNumbers(1, 2);
* var g = f(3);
* g(4);//=> 10
*/
var curryN = R.curryN = function curryN(length, fn) {
return (function recurry(args) {
return arity(Math.max(length - (args && args.length || 0), 0), function() {
if (arguments.length === 0) { throw noArgsException(); }
var newArgs = concat(args, arguments);
if (newArgs.length >= length) {
return fn.apply(this, newArgs);
} else {
return recurry(newArgs);
}
});
}([]));
};
/**
* Creates a new version of `fn` that, when invoked, will return either:
* - A new function ready to accept one or more of `fn`'s remaining arguments, if all of
* `fn`'s expected arguments have not yet been provided
* - `fn`'s result if all of its expected arguments have been provided
*
* @func
* @memberOf R
* @category core
* @category Function
* @sig (* -> a) -> (* -> a)
* @param {Function} fn The function to curry.
* @return {Function} A new, curried function.
* @see R.curryN
* @example
*
* var addFourNumbers = function(a, b, c, d) {
* return a + b + c + d;
* };
*
* var curriedAddFourNumbers = R.curry(addFourNumbers);
* var f = curriedAddFourNumbers(1, 2);
* var g = f(3);
* g(4);//=> 10
*/
var curry = R.curry = function curry(fn) {
return curryN(fn.length, fn);
};
/**
* Private function that determines whether or not a provided object has a given method.
* Does not ignore methods stored on the object's prototype chain. Used for dynamically
* dispatching Ramda methods to non-Array objects.
*
* @private
* @category Internal
* @param {string} methodName The name of the method to check for.
* @param {Object} obj The object to test.
* @return {boolean} `true` has a given method, `false` otherwise.
* @example
*
* var person = { name: 'John' };
* person.shout = function() { alert(this.name); };
*
* hasMethod('shout', person); //=> true
* hasMethod('foo', person); //=> false
*/
var hasMethod = function _hasMethod(methodName, obj) {
return obj && !isArray(obj) && typeof obj[methodName] === 'function';
};
/**
* Similar to hasMethod, this checks whether a function has a [methodname]
* function. If it isn't an array it will execute that function otherwise it will
* default to the ramda implementation.
*
* @private
* @category Internal
* @param {Function} fn ramda implemtation
* @param {String} methodname property to check for a custom implementation
* @return {Object} whatever the return value of the method is
*/
function checkForMethod(methodname, fn) {
return function(a, b, c) {
var length = arguments.length;
var obj = arguments[length - 1],
callBound = obj && !isArray(obj) && typeof obj[methodname] === 'function';
switch (arguments.length) {
case 0: return fn();
case 1: return callBound ? obj[methodname]() : fn(a);
case 2: return callBound ? obj[methodname](a) : fn(a, b);
case 3: return callBound ? obj[methodname](a, b) : fn(a, b, c);
}
};
}
/**
* Wraps a function of any arity (including nullary) in a function that accepts exactly `n`
* parameters. Any extraneous parameters will not be passed to the supplied function.
*
* @func
* @memberOf R
* @category Function
* @sig Number -> (* -> a) -> (* -> a)
* @param {number} n The desired arity of the new function.
* @param {Function} fn The function to wrap.
* @return {Function} A new function wrapping `fn`. The new function is guaranteed to be of
* arity `n`.
* @example
*
* var takesTwoArgs = function(a, b) {
* return [a, b];
* };
* takesTwoArgs.length; //=> 2
* takesTwoArgs(1, 2); //=> [1, 2]
*
* var takesOneArg = R.nAry(1, takesTwoArgs);
* takesOneArg.length; //=> 1
* // Only `n` arguments are passed to the wrapped function
* takesOneArg(1, 2); //=> [1, undefined]
*/
var nAry = R.nAry = function(n, fn) {
switch (n) {
case 0: return function() {return fn.call(this);};
case 1: return function(a0) {return fn.call(this, a0);};
case 2: return function(a0, a1) {return fn.call(this, a0, a1);};
case 3: return function(a0, a1, a2) {return fn.call(this, a0, a1, a2);};
case 4: return function(a0, a1, a2, a3) {return fn.call(this, a0, a1, a2, a3);};
case 5: return function(a0, a1, a2, a3, a4) {return fn.call(this, a0, a1, a2, a3, a4);};
case 6: return function(a0, a1, a2, a3, a4, a5) {return fn.call(this, a0, a1, a2, a3, a4, a5);};
case 7: return function(a0, a1, a2, a3, a4, a5, a6) {return fn.call(this, a0, a1, a2, a3, a4, a5, a6);};
case 8: return function(a0, a1, a2, a3, a4, a5, a6, a7) {return fn.call(this, a0, a1, a2, a3, a4, a5, a6, a7);};
case 9: return function(a0, a1, a2, a3, a4, a5, a6, a7, a8) {return fn.call(this, a0, a1, a2, a3, a4, a5, a6, a7, a8);};
case 10: return function(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9) {return fn.call(this, a0, a1, a2, a3, a4, a5, a6, a7, a8, a9);};
default: return fn; // TODO: or throw?
}
};
/**
* Wraps a function of any arity (including nullary) in a function that accepts exactly 1
* parameter. Any extraneous parameters will not be passed to the supplied function.
*
* @func
* @memberOf R
* @category Function
* @sig (* -> b) -> (a -> b)
* @param {Function} fn The function to wrap.
* @return {Function} A new function wrapping `fn`. The new function is guaranteed to be of
* arity 1.
* @example
*
* var takesTwoArgs = function(a, b) {
* return [a, b];
* };
* takesTwoArgs.length; //=> 2
* takesTwoArgs(1, 2); //=> [1, 2]
*
* var takesOneArg = R.unary(takesTwoArgs);
* takesOneArg.length; //=> 1
* // Only 1 argument is passed to the wrapped function
* takesOneArg(1, 2); //=> [1, undefined]
*/
R.unary = function _unary(fn) {
return nAry(1, fn);
};
/**
* Wraps a function of any arity (including nullary) in a function that accepts exactly 2
* parameters. Any extraneous parameters will not be passed to the supplied function.
*
* @func
* @memberOf R
* @category Function
* @sig (* -> c) -> (a, b -> c)
* @param {Function} fn The function to wrap.
* @return {Function} A new function wrapping `fn`. The new function is guaranteed to be of
* arity 2.
* @example
*
* var takesThreeArgs = function(a, b, c) {
* return [a, b, c];
* };
* takesThreeArgs.length; //=> 3
* takesThreeArgs(1, 2, 3); //=> [1, 2, 3]
*
* var takesTwoArgs = R.binary(takesThreeArgs);
* takesTwoArgs.length; //=> 2
* // Only 2 arguments are passed to the wrapped function
* takesTwoArgs(1, 2, 3); //=> [1, 2, undefined]
*/
R.binary = function _binary(fn) {
return nAry(2, fn);
};
/**
* Wraps a function of any arity (including nullary) in a function that accepts exactly `n`
* parameters. Unlike `nAry`, which passes only `n` arguments to the wrapped function,
* functions produced by `arity` will pass all provided arguments to the wrapped function.
*
* @func
* @memberOf R
* @sig (Number, (* -> *)) -> (* -> *)
* @category Function
* @param {number} n The desired arity of the returned function.
* @param {Function} fn The function to wrap.
* @return {Function} A new function wrapping `fn`. The new function is
* guaranteed to be of arity `n`.
* @example
*
* var takesTwoArgs = function(a, b) {
* return [a, b];
* };
* takesTwoArgs.length; //=> 2
* takesTwoArgs(1, 2); //=> [1, 2]
*
* var takesOneArg = R.arity(1, takesTwoArgs);
* takesOneArg.length; //=> 1
* // All arguments are passed through to the wrapped function
* takesOneArg(1, 2); //=> [1, 2]
*/
var arity = R.arity = function(n, fn) {
switch (n) {
case 0: return function() {return fn.apply(this, arguments);};
case 1: return function(a0) {void a0; return fn.apply(this, arguments);};
case 2: return function(a0, a1) {void a1; return fn.apply(this, arguments);};
case 3: return function(a0, a1, a2) {void a2; return fn.apply(this, arguments);};
case 4: return function(a0, a1, a2, a3) {void a3; return fn.apply(this, arguments);};
case 5: return function(a0, a1, a2, a3, a4) {void a4; return fn.apply(this, arguments);};
case 6: return function(a0, a1, a2, a3, a4, a5) {void a5; return fn.apply(this, arguments);};
case 7: return function(a0, a1, a2, a3, a4, a5, a6) {void a6; return fn.apply(this, arguments);};
case 8: return function(a0, a1, a2, a3, a4, a5, a6, a7) {void a7; return fn.apply(this, arguments);};
case 9: return function(a0, a1, a2, a3, a4, a5, a6, a7, a8) {void a8; return fn.apply(this, arguments);};
case 10: return function(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9) {void a9; return fn.apply(this, arguments);};
default: return fn; // TODO: or throw?
}
};
/**
* Turns a named method of an object (or object prototype) into a function
* that can be called directly.
*
* The returned function is curried and accepts `len + 1` parameters and
* the final parameter is the target object.
*
* @func
* @memberOf R
* @category Function
* @sig (Number, (a... -> b)) -> (a... -> c -> b)
* @param {number} len Number of arguments the returned function should take
* before the target object.
* @param {Function} method The method to wrap.
* @return {Function} A new curried function.
* @see R.invoker
* @example
*
* var sliceFrom = R.invokerN(1, String.prototype.slice);
* sliceFrom(6, 'abcdefghijklm'); //=> 'ghijklm'
*/
var invokerN = R.invokerN = function invokerN(len, method) {
return curryN(len + 1, function() {
var target = arguments[len];
return method.apply(target,
Array.prototype.slice.call(arguments, 0, len));
});
};
/**
* Turns a named method of an object (or object prototype) into a function that can be
* called directly.
*
* The returned function is curried and accepts `method.length + 1` parameters
* and the final parameter is the target object.
*
* @func
* @memberOf R
* @category Function
* @sig (a... -> b) -> (a... -> c -> b)
* @param {Function} method The method to wrap.
* @return {Function} A new curried function.
* @see R.invokerN
* @example
*
* var charAt = R.invoker(String.prototype.charAt);
* charAt(6, 'abcdefghijklm'); //=> 'g'
*
* var join = R.invoker(Array.prototype.join);
* var firstChar = charAt(0);
* join('', R.map(firstChar, ['light', 'ampliifed', 'stimulated', 'emission', 'radiation']));
* //=> 'laser'
*/
var invoker = R.invoker = function invoker(method) {
return invokerN(method.length, method);
};
/**
* Accepts a function `fn` and any number of transformer functions and returns a new
* function. When the new function is invoked, it calls the function `fn` with parameters
* consisting of the result of calling each supplied handler on successive arguments to the
* new function. For example:
*
* ```javascript
*
* var between = R.useWith(R.and,R.lt,R.gt)
*
* //This invocation
* var isTeen = between(12,20)
*
* //Is functionally equivalent to:
* var isTeen = R.and(R.gt(12), R.lt(20))
*
* isTeen(13) //=> true
* isTeen(45) //=> false
*
* ```
*
* If more arguments are passed to the returned function than transformer functions, those
* arguments are passed directly to `fn` as additional parameters. If you expect additional
* arguments that don't need to be transformed, although you can ignore them, it's best to
* pass an identity function so that the new function reports the correct arity.
*
* @func
* @memberOf R
* @category Function
* @sig ((* -> *), (* -> *)...) -> (* -> *)
* @param {Function} fn The function to wrap.
* @param {...Function} transformers A variable number of transformer functions
* @return {Function} The wrapped function.
* @example
*
* var double = function(y) { return y * 2; };
* var square = function(x) { return x * x; };
* var add = function(a, b) { return a + b; };
* // Adds any number of arguments together
* var addAll = function() {
* return R.reduce(add, 0, arguments);
* };
*
* // Basic example
* var addDoubleAndSquare = R.useWith(addAll, double, square);
*
* //≅ addAll(double(10), square(5));
* addDoubleAndSquare(10, 5); //=> 45
*
* // Example of passing more arguments than transformers
* //≅ addAll(double(10), square(5), 100);
* addDoubleAndSquare(10, 5, 100); //=> 145
*
* // But if you're expecting additional arguments that don't need transformation, it's best
* // to pass transformer functions so the resulting function has the correct arity
* var addDoubleAndSquareWithExtraParams = R.useWith(addAll, double, square, R.identity);
* //≅ addAll(double(10), square(5), R.identity(100));
* addDoubleAndSquare(10, 5, 100); //=> 145
*/
var useWith = R.useWith = function _useWith(fn /*, transformers */) {
var transformers = _slice(arguments, 1);
var tlen = transformers.length;
return curry(arity(tlen, function() {
var args = [], idx = -1;
while (++idx < tlen) {
args.push(transformers[idx](arguments[idx]));
}
return fn.apply(this, args.concat(_slice(arguments, tlen)));
}));
};
/**
* Iterate over an input `list`, calling a provided function `fn` for each element in the
* list.
*
* `fn` receives one argument: *(value)*.
*
* Note: `R.forEach` does not skip deleted or unassigned indices (sparse arrays), unlike
* the native `Array.prototype.forEach` method. For more details on this behavior, see:
* https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/forEach#Description
*
* Also note that, unlike `Array.prototype.forEach`, Ramda's `forEach` returns the original
* array. In some libraries this function is named `each`.
*
* @func
* @memberOf R
* @category List
* @sig (a -> *) -> [a] -> [a]
* @param {Function} fn The function to invoke. Receives one argument, `value`.
* @param {Array} list The list to iterate over.
* @return {Array} The original list.
* @example
*
* var printXPlusFive = function(x) { console.log(x + 5); };
* R.forEach(printXPlusFive, [1, 2, 3]); //=> [1, 2, 3]
* //-> 6
* //-> 7
* //-> 8
*/
function forEach(fn, list) {
var idx = -1, len = list.length;
while (++idx < len) {
fn(list[idx]);
}
// i can't bear not to return *something*
return list;
}
R.forEach = curry2(forEach);
/**
* Like `forEach`, but but passes additional parameters to the predicate function.
*
* `fn` receives three arguments: *(value, index, list)*.
*
* Note: `R.forEach.idx` does not skip deleted or unassigned indices (sparse arrays),
* unlike the native `Array.prototype.forEach` method. For more details on this behavior,
* see:
* https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/forEach#Description
*
* Also note that, unlike `Array.prototype.forEach`, Ramda's `forEach` returns the original
* array. In some libraries this function is named `each`.
*
* @func
* @memberOf R
* @category List
* @sig (a, i, [a] -> ) -> [a] -> [a]
* @param {Function} fn The function to invoke. Receives three arguments:
* (`value`, `index`, `list`).
* @param {Array} list The list to iterate over.
* @return {Array} The original list.
* @alias forEach.idx
* @example
*
* // Note that having access to the original `list` allows for
* // mutation. While you *can* do this, it's very un-functional behavior:
* var plusFive = function(num, idx, list) { list[idx] = num + 5 };
* R.forEach.idx(plusFive, [1, 2, 3]); //=> [6, 7, 8]
*/
R.forEach.idx = curry2(function forEachIdx(fn, list) {
var idx = -1, len = list.length;
while (++idx < len) {
fn(list[idx], idx, list);
}
// i can't bear not to return *something*
return list;
});
/**
* Creates a shallow copy of an array.
*
* @func
* @memberOf R
* @category core
* @category List
* @sig [a] -> [a]
* @param {Array} list The list to clone.
* @return {Array} A new copy of the original list.
* @example
*
* var numbers = [1, 2, 3];
* var numbersClone = R.clone(numbers); //=> [1, 2, 3]
* numbers === numbersClone; //=> false
*
* // Note that this is a shallow clone--it does not clone complex values:
* var objects = [{}, {}, {}];
* var objectsClone = R.clone(objects);
* objects[0] === objectsClone[0]; //=> true
*/
var clone = R.clone = function _clone(list) {
return _slice(list);
};
// Core Functions
// --------------
//
/**
* Reports whether an array is empty.
*
* @func
* @memberOf R
* @category List
* @sig [a] -> Boolean
* @param {Array} list The array to consider.
* @return {boolean} `true` if the `list` argument has a length of 0 or
* if `list` is a falsy value (e.g. undefined).
* @example
*
* R.isEmpty([1, 2, 3]); //=> false
* R.isEmpty([]); //=> true
* R.isEmpty(); //=> true
* R.isEmpty(null); //=> true
*/
function isEmpty(list) {
return !list || !list.length;
}
R.isEmpty = isEmpty;
/**
* Returns a new list with the given element at the front, followed by the contents of the
* list.
*
* @func
* @memberOf R
* @category core
* @category List
* @sig a -> [a] -> [a]
* @param {*} el The item to add to the head of the output list.
* @param {Array} list The array to add to the tail of the output list.
* @return {Array} A new array.
* @example
*
* R.prepend('fee', ['fi', 'fo', 'fum']); //=> ['fee', 'fi', 'fo', 'fum']
*/
R.prepend = curry2(function prepend(el, list) {
return concat([el], list);
});
/**
* @func
* @memberOf R
* @category List
* @see R.prepend
*/
R.cons = R.prepend;
/**
* Returns the first element in a list.
* In some libraries this function is named `first`.
*
* @func
* @memberOf R
* @category core
* @category List
* @sig [a] -> a
* @param {Array} [list=[]] The array to consider.
* @return {*} The first element of the list, or `undefined` if the list is empty.
* @example
*
* R.head(['fi', 'fo', 'fum']); //=> 'fi'
*/
R.head = function head(list) {
list = list || [];
return list[0];
};
/**
* @func
* @memberOf R
* @category List
* @see R.head
*/
R.car = R.head;
/**
* Returns the last element from a list.
*
* @func
* @memberOf R
* @category List
* @sig [a] -> a
* @param {Array} [list=[]] The array to consider.
* @return {*} The last element of the list, or `undefined` if the list is empty.
* @example
*
* R.last(['fi', 'fo', 'fum']); //=> 'fum'
*/
R.last = function _last(list) {
list = list || [];
return list[list.length - 1];
};
/**
* Returns all but the first element of a list. If the list provided has the `tail` method,
* it will instead return `list.tail()`.
*
* @func
* @memberOf R
* @category core
* @category List
* @sig [a] -> [a]
* @param {Array} [list=[]] The array to consider.
* @return {Array} A new array containing all but the first element of the input list, or an
* empty list if the input list is a falsy value (e.g. `undefined`).
* @example
*
* R.tail(['fi', 'fo', 'fum']); //=> ['fo', 'fum']
*/
R.tail = checkForMethod('tail', function(list) {
list = list || [];
return (list.length > 1) ? _slice(list, 1) : [];
});
/**
* @func
* @memberOf R
* @category List
* @see R.tail
*/
R.cdr = R.tail;
/**
* Returns a new list containing the contents of the given list, followed by the given
* element.
*
* @func
* @memberOf R
* @category core
* @category List
* @sig a -> [a] -> [a]
* @param {*} el The element to add to the end of the new list.
* @param {Array} list The list whose contents will be added to the beginning of the output
* list.
* @return {Array} A new list containing the contents of the old list followed by `el`.
* @example
*
* R.append('tests', ['write', 'more']); //=> ['write', 'more', 'tests']
* R.append('tests', []); //=> ['tests']
* R.append(['tests'], ['write', 'more']); //=> ['write', 'more', ['tests']]
*/
var append = R.append = curry2(function _append(el, list) {
return concat(list, [el]);
});
/**
* @func
* @memberOf R
* @category List
* @see R.append
*/
R.push = R.append;
/**
* Returns a new list consisting of the elements of the first list followed by the elements
* of the second.
*
* @func
* @memberOf R
* @category core
* @category List
* @sig [a] -> [a] -> [a]
* @param {Array} list1 The first list to merge.
* @param {Array} list2 The second set to merge.
* @return {Array} A new array consisting of the contents of `list1` followed by the
* contents of `list2`. If, instead of an Array for `list1`, you pass an
* object with a `concat` method on it, `concat` will call `list1.concat`
* and pass it the value of `list2`.
* @example
*
* R.concat([], []); //=> []
* R.concat([4, 5, 6], [1, 2, 3]); //=> [4, 5, 6, 1, 2, 3]
* R.concat('ABC', 'DEF'); // 'ABCDEF'
*/
R.concat = curry2(function(set1, set2) {
if (isArray(set2)) {
return concat(set1, set2);
} else if (hasMethod('concat', set1)) {
return set1.concat(set2);
} else {
throw new TypeError("can't concat " + typeof set1);
}
});
/**
* A function that does nothing but return the parameter supplied to it. Good as a default
* or placeholder function.
*
* @func
* @memberOf R
* @category Core
* @sig a -> a
* @param {*} x The value to return.
* @return {*} The input value, `x`.
* @example
*
* R.identity(1); //=> 1
*
* var obj = {};
* R.identity(obj) === obj; //=> true
*/
var identity = R.identity = function _I(x) {
return x;
};
/**
* @func
* @memberOf R
* @category Core
* @see R.identity
*/
R.I = R.identity;
/**
* Calls an input function `n` times, returning an array containing the results of those
* function calls.
*
* `fn` is passed one argument: The current value of `n`, which begins at `0` and is
* gradually incremented to `n - 1`.
*
* @func
* @memberOf R
* @category List
* @sig (i -> a) -> i -> [a]
* @param {Function} fn The function to invoke. Passed one argument, the current value of `n`.
* @param {number} n A value between `0` and `n - 1`. Increments after each function call.
* @return {Array} An array containing the return values of all calls to `fn`.
* @example
*
* R.times(R.identity, 5); //=> [0, 1, 2, 3, 4]
*/
R.times = curry2(function _times(fn, n) {
var list = new Array(n);
var idx = -1;
while (++idx < n) {
list[idx] = fn(idx);
}
return list;
});
/**
* Returns a fixed list of size `n` containing a specified identical value.
*
* @func
* @memberOf R
* @category List
* @sig a -> n -> [a]
* @param {*} value The value to repeat.
* @param {number} n The desired size of the output list.
* @return {Array} A new array containing `n` `value`s.
* @example
*
* R.repeatN('hi', 5); //=> ['hi', 'hi', 'hi', 'hi', 'hi']
*
* var obj = {};
* var repeatedObjs = R.repeatN(obj, 5); //=> [{}, {}, {}, {}, {}]
* repeatedObjs[0] === repeatedObjs[1]; //=> true
*/
R.repeatN = curry2(function _repeatN(value, n) {
return R.times(R.always(value), n);
});
// Function functions :-)
// ----------------------
//
// These functions make new functions out of old ones.
// --------
/**
* Applies function `fn` to the argument list `args`. This is useful for
* creating a fixed-arity function from a variadic function. `fn` should
* be a bound function if context is significant.
*
* @func
* @memberOf R
* @category core
* @category Function
* @sig (*... -> a) -> [*] -> a
* @param {Function} fn
* @param {Array} args
* @return {*}
* @example
*
* var nums = [1, 2, 3, -99, 42, 6, 7];
* R.apply(Math.max, nums); //=> 42
*/
R.apply = curry2(function _apply(fn, args) {
return fn.apply(this, args);
});
/**
* Basic, right-associative composition function. Accepts two functions and returns the
* composite function; this composite function represents the operation `var h = f(g(x))`,
* where `f` is the first argument, `g` is the second argument, and `x` is whatever
* argument(s) are passed to `h`.
*
* This function's main use is to build the more general `compose` function, which accepts
* any number of functions.
*
* @private
* @category Function
* @param {Function} f A function.
* @param {Function} g A function.
* @return {Function} A new function that is the equivalent of `f(g(x))`.
* @example
*
* var double = function(x) { return x * 2; };
* var square = function(x) { return x * x; };
* var squareThenDouble = internalCompose(double, square);
*
* squareThenDouble(5); //≅ double(square(5)) => 50
*/
function internalCompose(f, g) {
return function() {
return f.call(this, g.apply(this, arguments));
};
}
/**
* Creates a new function that runs each of the functions supplied as parameters in turn,
* passing the return value of each function invocation to the next function invocation,
* beginning with whatever arguments were passed to the initial invocation.
*
* Note that `compose` is a right-associative function, which means the functions provided
* will be invoked in order from right to left. In the example `var h = compose(f, g)`,
* the function `h` is equivalent to `f( g(x) )`, where `x` represents the arguments
* originally passed to `h`.
*
* @func
* @memberOf R
* @category core
* @category Function
* @sig ((y -> z), (x -> y), ..., (b -> c), (a... -> b)) -> (a... -> z)
* @param {...Function} functions A variable number of functions.
* @return {Function} A new function which represents the result of calling each of the
* input `functions`, passing the result of each function call to the next, from
* right to left.
* @example
*
* var triple = function(x) { return x * 3; };
* var double = function(x) { return x * 2; };
* var square = function(x) { return x * x; };
* var squareThenDoubleThenTriple = R.compose(triple, double, square);
*
* //≅ triple(double(square(5)))
* squareThenDoubleThenTriple(5); //=> 150
*/
var compose = R.compose = function _compose() {
switch (arguments.length) {
case 0: throw noArgsException();
case 1: return arguments[0];
default:
var idx = arguments.length - 1, fn = arguments[idx], length = fn.length;
while (idx--) {
fn = internalCompose(arguments[idx], fn);
}
return arity(length, fn);
}
};
/**
* Creates a new function that runs each of the functions supplied as parameters in turn,
* passing the return value of each function invocation to the next function invocation,
* beginning with whatever arguments were passed to the initial invocation.
*
* `pipe` is the mirror version of `compose`. `pipe` is left-associative, which means that
* each of the functions provided is executed in order from left to right.
*
* In some libraries this function is named `sequence`.
* @func
* @memberOf R
* @category Function
* @sig ((a... -> b), (b -> c), ..., (x -> y), (y -> z)) -> (a... -> z)
* @param {...Function} functions A variable number of functions.
* @return {Function} A new function which represents the result of calling each of the
* input `functions`, passing the result of each function call to the next, from
* right to left.
* @example
*
* var triple = function(x) { return x * 3; };
* var double = function(x) { return x * 2; };
* var square = function(x) { return x * x; };
* var squareThenDoubleThenTriple = R.pipe(square, double, triple);
*
* //≅ triple(double(square(5)))
* squareThenDoubleThenTriple(5); //=> 150
*/
R.pipe = function _pipe() {
return compose.apply(this, R.reverse(arguments));
};
/**
* Returns a new function much like the supplied one, except that the first two arguments'
* order is reversed.
*
* @func
* @memberOf R
* @category Function
* @sig (a -> b -> c -> ... -> z) -> (b -> a -> c -> ... -> z)
* @param {Function} fn The function to invoke with its first two parameters reversed.
* @return {*} The result of invoking `fn` with its first two parameters' order reversed.
* @example
*
* var mergeThree = function(a, b, c) {
* return ([]).concat(a, b, c);
* };
*
* mergeThree(1, 2, 3); //=> [1, 2, 3]
*
* R.flip(mergeThree)(1, 2, 3); //=> [2, 1, 3]
*/
var flip = R.flip = function _flip(fn) {
return function(a, b) {
switch (arguments.length) {
case 0: throw noArgsException();
case 1: return function(b) { return fn.apply(this, [b, a].concat(_slice(arguments, 1))); };
default: return fn.apply(this, concat([b, a], _slice(arguments, 2)));
}
};
};
/**
* Accepts as its arguments a function and any number of values and returns a function that,
* when invoked, calls the original function with all of the values prepended to the
* original function's arguments list. In some libraries this function is named `applyLeft`.
*
* @func
* @memberOf R
* @category Function
* @sig (a -> b -> ... -> i -> j -> ... -> m -> n) -> a -> b-> ... -> i -> (j -> ... -> m -> n)
* @param {Function} fn The function to invoke.
* @param {...*} [args] Arguments to prepend to `fn` when the returned function is invoked.
* @return {Function} A new function wrapping `fn`. When invoked, it will call `fn`
* with `args` prepended to `fn`'s arguments list.
* @example
*
* var multiply = function(a, b) { return a * b; };
* var double = R.lPartial(multiply, 2);
* double(2); //=> 4
*
* var greet = function(salutation, title, firstName, lastName) {
* return salutation + ', ' + title + ' ' + firstName + ' ' + lastName + '!';
* };
* var sayHello = R.lPartial(greet, 'Hello');
* var sayHelloToMs = R.lPartial(sayHello, 'Ms.');
* sayHelloToMs('Jane', 'Jones'); //=> 'Hello, Ms. Jane Jones!'
*/
R.lPartial = function _lPartial(fn /*, args */) {
var args = _slice(arguments, 1);
return arity(Math.max(fn.length - args.length, 0), function() {
return fn.apply(this, concat(args, arguments));
});
};
/**
* Accepts as its arguments a function and any number of values and returns a function that,
* when invoked, calls the original function with all of the values appended to the original
* function's arguments list.
*
* Note that `rPartial` is the opposite of `lPartial`: `rPartial` fills `fn`'s arguments
* from the right to the left. In some libraries this function is named `applyRight`.
*
* @func
* @memberOf R
* @category Function
* @sig (a -> b-> ... -> i -> j -> ... -> m -> n) -> j -> ... -> m -> n -> (a -> b-> ... -> i)
* @param {Function} fn The function to invoke.
* @param {...*} [args] Arguments to append to `fn` when the returned function is invoked.
* @return {Function} A new function wrapping `fn`. When invoked, it will call `fn` with
* `args` appended to `fn`'s arguments list.
* @example
*
* var greet = function(salutation, title, firstName, lastName) {
* return salutation + ', ' + title + ' ' + firstName + ' ' + lastName + '!';
* };
* var greetMsJaneJones = R.rPartial(greet, 'Ms.', 'Jane', 'Jones');
*
* greetMsJaneJones('Hello'); //=> 'Hello, Ms. Jane Jones!'
*/
R.rPartial = function _rPartial(fn) {
var args = _slice(arguments, 1);
return arity(Math.max(fn.length - args.length, 0), function() {
return fn.apply(this, concat(arguments, args));
});
};
/**
* Creates a new function that, when invoked, caches the result of calling `fn` for a given
* argument set and returns the result. Subsequent calls to the memoized `fn` with the same
* argument set will not result in an additional call to `fn`; instead, the cached result
* for that set of arguments will be returned.
*
* Note that this version of `memoize` effectively handles only string and number
* parameters. Also note that it does not work on variadic functions.
*
* @func
* @memberOf R
* @category Function
* @sig (a... -> b) -> (a... -> b)
* @param {Function} fn The function to be wrapped by `memoize`.
* @return {Function} Returns a memoized version of `fn`.
* @example
*
* var numberOfCalls = 0;
* var trackedAdd = function(a, b) {
* numberOfCalls += 1;
* return a + b;
* };
* var memoTrackedAdd = R.memoize(trackedAdd);
*
* memoTrackedAdd(1, 2); //=> 3
* numberOfCalls; //=> 1
* memoTrackedAdd(1, 2); //=> 3
* numberOfCalls; //=> 1
* memoTrackedAdd(2, 3); //=> 5
* numberOfCalls; //=> 2
*
* // Note that argument order matters
* memoTrackedAdd(2, 1); //=> 3
* numberOfCalls; //=> 3
*/
R.memoize = function _memoize(fn) {
if (!fn.length) {
return once(fn);
}
var cache = {};
return function() {
if (!arguments.length) {return;}
var position = foldl(function(cache, arg) {
return cache[arg] || (cache[arg] = {});
}, cache, _slice(arguments, 0, arguments.length - 1));
var arg = arguments[arguments.length - 1];
return (position[arg] || (position[arg] = fn.apply(this, arguments)));
};
};
/**
* Accepts a function `fn` and returns a function that guards invocation of `fn` such that
* `fn` can only ever be called once, no matter how many times the returned function is
* invoked.
*
* @func
* @memberOf R
* @category Function
* @sig (a... -> b) -> (a... -> b)
* @param {Function} fn The function to wrap in a call-only-once wrapper.
* @return {Function} The wrapped function.
* @example
*
* var addOneOnce = R.once(function(x){ return x + 1; });
* addOneOnce(10); //=> 11
* addOneOnce(addOneOnce(50)); //=> 11
*/
var once = R.once = function _once(fn) {
var called = false, result;
return function() {
if (called) {
return result;
}
called = true;
result = fn.apply(this, arguments);
return result;
};
};
/**
* Wrap a function inside another to allow you to make adjustments to the parameters, or do
* other processing either before the internal function is called or with its results.
*
* @func
* @memberOf R
* @category Function
* @sig ((* -> *) -> ((* -> *), a...) -> (*, a... -> *)
* @param {Function} fn The function to wrap.
* @param {Function} wrapper The wrapper function.
* @return {Function} The wrapped function.
* @example
*
* var slashify = R.wrap(R.flip(add)('/'), function(f, x) {
* return R.match(/\/$/, x) ? x : f(x);
* });
*
* slashify('a'); //=> 'a/'
* slashify('a/'); //=> 'a/'
*/
R.wrap = function _wrap(fn, wrapper) {
return function() {
return wrapper.apply(this, concat([fn], arguments));
};
};
/**
* Wraps a constructor function inside a curried function that can be called with the same
* arguments and returns the same type. The arity of the function returned is specified
* to allow using variadic constructor functions.
*
* NOTE: Does not work with some built-in objects such as Date.
*
* @func
* @memberOf R
* @category Function
* @sig Number -> (* -> {*}) -> (* -> {*})
* @param {number} n The arity of the constructor function.
* @param {Function} Fn The constructor function to wrap.
* @return {Function} A wrapped, curried constructor function.
* @example
*
* // Variadic constructor function
* var Widget = function() {
* this.children = Array.prototype.slice.call(arguments);
* // ...
* };
* Widget.prototype = {
* // ...
* };
* var allConfigs = {
* // ...
* };
* R.map(R.constructN(1, Widget), allConfigs); // a list of Widgets
*/
var constructN = R.constructN = curry2(function _constructN(n, Fn) {
var f = function() {
var Temp = function() {}, inst, ret;
Temp.prototype = Fn.prototype;
inst = new Temp();
ret = Fn.apply(inst, arguments);
return Object(ret) === ret ? ret : inst;
};
return n > 1 ? curry(nAry(n, f)) : f;
});
/**
* Wraps a constructor function inside a curried function that can be called with the same
* arguments and returns the same type.
*
* NOTE: Does not work with some built-in objects such as Date.
*
* @func
* @memberOf R
* @category Function
* @sig (* -> {*}) -> (* -> {*})
* @param {Function} Fn The constructor function to wrap.
* @return {Function} A wrapped, curried constructor function.
* @example
*
* // Constructor function
* var Widget = function(config) {
* // ...
* };
* Widget.prototype = {
* // ...
* };
* var allConfigs = {
* // ...
* };
* R.map(R.construct(Widget), allConfigs); // a list of Widgets
*/
R.construct = function _construct(Fn) {
return constructN(Fn.length, Fn);
};
/**
* Accepts three functions and returns a new function. When invoked, this new function will
* invoke the first function, `after`, passing as its arguments the results of invoking the
* second and third functions with whatever arguments are passed to the new function.
*
* For example, a function produced by `converge` is equivalent to:
*
* ```javascript
* var h = R.converge(e, f, g);
* h(1, 2); //≅ e( f(1, 2), g(1, 2) )
* ```
*
* @func
* @memberOf R
* @category Function
* @sig ((a, b -> c) -> (((* -> a), (* -> b), ...) -> c)
* @param {Function} after A function. `after` will be invoked with the return values of
* `fn1` and `fn2` as its arguments.
* @param {Function} fn1 A function. It will be invoked with the arguments passed to the
* returned function. Afterward, its resulting value will be passed to `after` as
* its first argument.
* @param {Function} fn2 A function. It will be invoked with the arguments passed to the
* returned function. Afterward, its resulting value will be passed to `after` as
* its second argument.
* @return {Function} A new function.
* @example
*
* var add = function(a, b) { return a + b; };
* var multiply = function(a, b) { return a * b; };
* var subtract = function(a, b) { return a - b; };
*
* //≅ multiply( add(1, 2), subtract(1, 2) );
* R.converge(multiply, add, subtract)(1, 2); //=> -3
*/
R.converge = function(after) {
var fns = _slice(arguments, 1);
return function() {
var args = arguments;
return after.apply(this, map(function(fn) {
return fn.apply(this, args);
}, fns));
};
};
// List Functions
// --------------
//
// These functions operate on logical lists, here plain arrays. Almost all of these are curried, and the list
// parameter comes last, so you can create a new function by supplying the preceding arguments, leaving the
// list parameter off. For instance:
//
// // skip third parameter
// var checkAllPredicates = reduce(andFn, alwaysTrue);
// // ... given suitable definitions of odd, lt20, gt5
// var test = checkAllPredicates([odd, lt20, gt5]);
// // test(7) => true, test(9) => true, test(10) => false,
// // test(3) => false, test(21) => false,
// --------
/**
* Returns a single item by iterating through the list, successively calling the iterator
* function and passing it an accumulator value and the current value from the array, and
* then passing the result to the next call.
*
* The iterator function receives two values: *(acc, value)*
*
* Note: `R.reduce` does not skip deleted or unassigned indices (sparse arrays), unlike
* the native `Array.prototype.reduce` method. For more details on this behavior, see:
* https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/reduce#Description
*
* @func
* @memberOf R
* @category core
* @category List
* @sig (a,b -> a) -> a -> [b] -> a
* @param {Function} fn The iterator function. Receives two values, the accumulator and the
* current element from the array.
* @param {*} acc The accumulator value.
* @param {Array} list The list to iterate over.
* @return {*} The final, accumulated value.
* @example
*
* var numbers = [1, 2, 3];
* var add = function(a, b) {
* return a + b;
* };
*
* R.reduce(add, 10, numbers); //=> 16
*/
R.reduce = curry3(function _reduce(fn, acc, list) {
var idx = -1, len = list.length;
while (++idx < len) {
acc = fn(acc, list[idx]);
}
return acc;
});
/**
* @func
* @memberOf R
* @category List
* @see R.reduce
*/
var foldl = R.foldl = R.reduce;
/**
* Like `reduce`, but passes additional parameters to the predicate function.
*
* The iterator function receives four values: *(acc, value, index, list)*
*
* Note: `R.reduce.idx` does not skip deleted or unassigned indices (sparse arrays),
* unlike the native `Array.prototype.reduce` method. For more details on this behavior,
* see:
* https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/reduce#Description
*
* @func
* @memberOf R
* @category core
* @category List
* @sig (a,b,i,[b] -> a) -> a -> [b] -> a
* @param {Function} fn The iterator function. Receives four values: the accumulator, the
* current element from `list`, that element's index, and the entire `list` itself.
* @param {*} acc The accumulator value.
* @param {Array} list The list to iterate over.
* @return {*} The final, accumulated value.
* @alias reduce.idx
* @example
*
* var letters = ['a', 'b', 'c'];
* var objectify = function(accObject, elem, idx, list) {
* accObject[elem] = idx;
* return accObject;
* };
*
* R.reduce.idx(objectify, {}, letters); //=> { 'a': 0, 'b': 1, 'c': 2 }
*/
R.reduce.idx = curry3(function _reduceIdx(fn, acc, list) {
var idx = -1, len = list.length;
while (++idx < len) {
acc = fn(acc, list[idx], idx, list);
}
return acc;
});
/**
* @func
* @memberOf R
* @category core
* @category List
* @alias foldl.idx
* @see R.reduce.idx
*/
R.foldl.idx = R.reduce.idx;
/**
* Returns a single item by iterating through the list, successively calling the iterator
* function and passing it an accumulator value and the current value from the array, and
* then passing the result to the next call.
*
* Similar to `reduce`, except moves through the input list from the right to the left.
*
* The iterator function receives two values: *(acc, value)*
*
* Note: `R.reduce` does not skip deleted or unassigned indices (sparse arrays), unlike
* the native `Array.prototype.reduce` method. For more details on this behavior, see:
* https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/reduce#Description
*
* @func
* @memberOf R
* @category core
* @category List
* @sig (a,b -> a) -> a -> [b] -> a
* @param {Function} fn The iterator function. Receives two values, the accumulator and the
* current element from the array.
* @param {*} acc The accumulator value.
* @param {Array} list The list to iterate over.
* @return {*} The final, accumulated value.
* @example
*
* var pairs = [ ['a', 1], ['b', 2], ['c', 3] ];
* var flattenPairs = function(acc, pair) {
* return acc.concat(pair);
* };
*
* R.reduceRight(flattenPairs, [], pairs); //=> [ 'c', 3, 'b', 2, 'a', 1 ]
*/
R.reduceRight = curry3(checkForMethod('reduceRight', function _reduceRight(fn, acc, list) {
var idx = list.length;
while (idx--) {
acc = fn(acc, list[idx]);
}
return acc;
}));
/**
* @func
* @memberOf R
* @category core
* @category List
* @see R.reduceRight
*/
R.foldr = R.reduceRight;
/**
* Like `reduceRight`, but passes additional parameters to the predicate function. Moves through
* the input list from the right to the left.
*
* The iterator function receives four values: *(acc, value, index, list)*.
*
* Note: `R.reduceRight.idx` does not skip deleted or unassigned indices (sparse arrays),
* unlike the native `Array.prototype.reduce` method. For more details on this behavior,
* see:
* https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/reduce#Description
*
* @func
* @memberOf R
* @category core
* @category List
* @sig (a,b,i,[b] -> a -> [b] -> a
* @param {Function} fn The iterator function. Receives four values: the accumulator, the
* current element from `list`, that element's index, and the entire `list` itself.
* @param {*} acc The accumulator value.
* @param {Array} list The list to iterate over.
* @return {*} The final, accumulated value.
* @alias reduceRight.idx
* @example
*
* var letters = ['a', 'b', 'c'];
* var objectify = function(accObject, elem, idx, list) {
* accObject[elem] = idx;
* return accObject;
* };
*
* R.reduceRight.idx(objectify, {}, letters); //=> { 'c': 2, 'b': 1, 'a': 0 }
*/
R.reduceRight.idx = curry3(function _reduceRightIdx(fn, acc, list) {
var idx = list.length;
while (idx--) {
acc = fn(acc, list[idx], idx, list);
}
return acc;
});
/**
* @func
* @memberOf R
* @category List
* @alias foldr.idx
* @see R.reduceRight.idx
*/
R.foldr.idx = R.reduceRight.idx;
/**
* Builds a list from a seed value. Accepts an iterator function, which returns either false
* to stop iteration or an array of length 2 containing the value to add to the resulting
* list and the seed to be used in the next call to the iterator function.
*
* The iterator function receives one argument: *(seed)*.
*
* @func
* @memberOf R
* @category List
* @sig (a -> [b]) -> * -> [b]
* @param {Function} fn The iterator function. receives one argument, `seed`, and returns
* either false to quit iteration or an array of length two to proceed. The element
* at index 0 of this array will be added to the resulting array, and the element
* at index 1 will be passed to the next call to `fn`.
* @param {*} seed The seed value.
* @return {Array} The final list.
* @example
*
* var f = function(n) { return n > 50 ? false : [-n, n + 10] };
* R.unfoldr(f, 10); //=> [-10, -20, -30, -40, -50]
*/
R.unfoldr = curry2(function _unfoldr(fn, seed) {
var pair = fn(seed);
var result = [];
while (pair && pair.length) {
result.push(pair[0]);
pair = fn(pair[1]);
}
return result;
});
/**
* Returns a new list, constructed by applying the supplied function to every element of the
* supplied list.
*
* Note: `R.map` does not skip deleted or unassigned indices (sparse arrays), unlike the
* native `Array.prototype.map` method. For more details on this behavior, see:
* https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/map#Description
*
* @func
* @memberOf R
* @category core
* @category List
* @sig (a -> b) -> [a] -> [b]
* @param {Function} fn The function to be called on every element of the input `list`.
* @param {Array} list The list to be iterated over.
* @return {Array} The new list.
* @example
*
* var double = function(x) {
* return x * 2;
* };
*
* R.map(double, [1, 2, 3]); //=> [2, 4, 6]
*/
function map(fn, list) {
var idx = -1, len = list.length, result = new Array(len);
while (++idx < len) {
result[idx] = fn(list[idx]);
}
return result;
}
R.map = curry2(checkForMethod('map', map));
/**
* Like `map`, but but passes additional parameters to the mapping function.
* `fn` receives three arguments: *(value, index, list)*.
*
* Note: `R.map.idx` does not skip deleted or unassigned indices (sparse arrays), unlike
* the native `Array.prototype.map` method. For more details on this behavior, see:
* https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/map#Description
*
* @func
* @memberOf R
* @category core
* @category List
* @sig (a,i,[b] -> b) -> [a] -> [b]
* @param {Function} fn The function to be called on every element of the input `list`.
* @param {Array} list The list to be iterated over.
* @return {Array} The new list.
* @alias map.idx
* @example
*
* var squareEnds = function(elt, idx, list) {
* if (idx === 0 || idx === list.length - 1) {
* return elt * elt;
* }
* return elt;
* };
*
* R.map.idx(squareEnds, [8, 5, 3, 0, 9]); //=> [64, 5, 3, 0, 81]
*/
R.map.idx = curry2(function _mapIdx(fn, list) {
var idx = -1, len = list.length, result = new Array(len);
while (++idx < len) {
result[idx] = fn(list[idx], idx, list);
}
return result;
});
/**
* Map, but for objects. Creates an object with the same keys as `obj` and values
* generated by running each property of `obj` through `fn`. `fn` is passed one argument:
* *(value)*.
*
* @func
* @memberOf R
* @category List
* @sig (v -> v) -> {k: v} -> {k: v}
* @param {Function} fn A function called for each property in `obj`. Its return value will
* become a new property on the return object.
* @param {Object} obj The object to iterate over.
* @return {Object} A new object with the same keys as `obj` and values that are the result
* of running each property through `fn`.
* @example
*
* var values = { x: 1, y: 2, z: 3 };
* var double = function(num) {
* return num * 2;
* };
*
* R.mapObj(double, values); //=> { x: 2, y: 4, z: 6 }
*/
// TODO: consider mapObj.key in parallel with mapObj.idx. Also consider folding together with `map` implementation.
R.mapObj = curry2(function _mapObject(fn, obj) {
return foldl(function(acc, key) {
acc[key] = fn(obj[key]);
return acc;
}, {}, keys(obj));
});
/**
* Like `mapObj`, but but passes additional arguments to the predicate function. The
* predicate function is passed three arguments: *(value, key, obj)*.
*
* @func
* @memberOf R
* @category List
* @sig (v, k, {k: v} -> v) -> {k: v} -> {k: v}
* @param {Function} fn A function called for each property in `obj`. Its return value will
* become a new property on the return object.
* @param {Object} obj The object to iterate over.
* @return {Object} A new object with the same keys as `obj` and values that are the result
* of running each property through `fn`.
* @alias mapObj.idx
* @example
*
* var values = { x: 1, y: 2, z: 3 };
* var prependKeyAndDouble = function(num, key, obj) {
* return key + (num * 2);
* };
*
* R.mapObj.idx(prependKeyAndDouble, values); //=> { x: 'x2', y: 'y4', z: 'z6' }
*/
R.mapObj.idx = curry2(function mapObjectIdx(fn, obj) {
return foldl(function(acc, key) {
acc[key] = fn(obj[key], key, obj);
return acc;
}, {}, keys(obj));
});
/**
* Scanl is similar to reduce, but returns a list of successively reduced values from the left
*
* @func
* @memberOf R
* @category List
* @sig (a,b -> a) -> a -> [b] -> [a]
* @param {Function} fn The iterator function. Receives two values, the accumulator and the
* current element from the array
* @param {*} acc The accumulator value.
* @param {Array} list The list to iterate over.
* @return {Array} A list of all intermediately reduced values
* @example
*
* var numbers = [1, 2, 3, 4];
* var factorials = R.scanl(R.multiply, 1, numbers); //=> [1, 1, 2, 6, 24]
*/
R.scanl = curry3(function _scanl(fn, acc, list) {
var idx = 0, len = list.length + 1, result = new Array(len);
result[idx] = acc;
while (++idx < len) {
acc = fn(acc, list[idx - 1]);
result[idx] = acc;
}
return result;
});
/**
* "lifts" a function to be the specified arity, so that it may "map over" that many
* lists (or other Functors).
*
* @func
* @memberOf R
* @see R.lift
* @category Function
* @sig Number -> (*... -> *) -> ([*]... -> [*])
* @param {Function} fn The function to lift into higher context
* @return {Function} The function `fn` applicable to mappable objects.
* @example
*
* var madd3 = R.liftN(3, R.curryN(3, function() {
* return R.foldl(R.add, 0, arguments);
* }));
* madd3([1,2,3], [1,2,3], [1]); //=> [3, 4, 5, 4, 5, 6, 5, 6, 7]
*/
R.liftN = curry2(function liftN(arity, fn) {
var lifted = curryN(arity, fn);
if (arguments.length === 0) {
throw noArgsException();
}
return R.curryN(arity, function() {
return R.foldl(R.ap, R.map(lifted, arguments[0]), _slice(arguments, 1));
});
});
/**
* "lifts" a function of arity > 1 so that it may "map over" an Array or
* other Functor.
*
* @func
* @memberOf R
* @see R.liftN
* @category Function
* @sig (*... -> *) -> ([*]... -> [*])
* @param {Function} fn The function to lift into higher context
* @return {Function} The function `fn` applicable to mappable objects.
* @example
*
* var madd3 = R.lift(R.curryN(3, function(a, b, c) {
* return a + b + c;
* }));
* madd3([1,2,3], [1,2,3], [1]); //=> [3, 4, 5, 4, 5, 6, 5, 6, 7]
*
* var madd5 = R.lift(R.curryN(5, function(a, b, c, d, e) {
* return a + b + c + d + e;
* }));
* madd5([1,2], [3], [4, 5], [6], [7, 8]); //=> [21, 22, 22, 23, 22, 23, 23, 24]
*/
R.lift = function lift(fn) {
if (arguments.length === 0) {
throw noArgsException();
}
return R.liftN(fn.length, fn);
};
/**
* ap applies a list of functions to a list of values.
*
* @func
* @memberOf R
* @category Function
* @sig [f] -> [a] -> [f a]
* @param {Array} fns An array of functions
* @param {Array} vs An array of values
* @return the value of applying each the function `fns` to each value in `vs`
* @example
*
* R.ap([R.multiply(2), R.add(3)], [1,2,3]); //=> [2, 4, 6, 4, 5, 6]
*/
R.ap = curry2(function _ap(fns, vs) {
return hasMethod('ap', fns) ? fns.ap(vs) : foldl(function(acc, fn) {
return concat(acc, map(fn, vs));
}, [], fns);
});
/**
*
* `of` wraps any object in an Array. This implementation is compatible with the
* Fantasy-land Applicative spec, and will work with types that implement that spec.
* Note this `of` is different from the ES6 `of`; See
* https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/of
*
* @func
* @memberOf R
* @category Function
* @sig a -> [a]
* @param {*} x any value
* @return [x]
* @example
*
* R.of(1); //=> [1]
* R.of([2]); //=> [[2]]
* R.of({}); //=> [{}]
*/
R.of = function _of(x, container) {
return (hasMethod('of', container)) ? container.of(x) : [x];
};
/**
* `empty` wraps any object in an array. This implementation is compatible with the
* Fantasy-land Monoid spec, and will work with types that implement that spec.
*
* @func
* @memberOf R
* @category Function
* @sig * -> []
* @return {Array} an empty array
* @example
*
* R.empty([1,2,3,4,5]); //=> []
*/
R.empty = function _empty(x) {
return (hasMethod('empty', x)) ? x.empty() : [];
};
/**
* `chain` maps a function over a list and concatenates the results.
* This implementation is compatible with the
* Fantasy-land Chain spec, and will work with types that implement that spec.
* `chain` is also known as `flatMap` in some libraries
*
* @func
* @memberOf R
* @category List
* @sig (a -> [b]) -> [a] -> [b]
* @param {Function} fn
* @param {Array} list
* @return {Array}
* @example
*
* var duplicate = function(n) {
* return [n, n];
* };
* R.chain(duplicate, [1, 2, 3]); //=> [1, 1, 2, 2, 3, 3]
*
*/
R.chain = curry2(checkForMethod('chain', function _chain(f, list) {
return unnest(map(f, list));
}));
/**
* Returns the number of elements in the array by returning `list.length`.
*
* @func
* @memberOf R
* @category List
* @sig [a] -> Number
* @param {Array} list The array to inspect.
* @return {number} The size of the array.
* @example
*
* R.size([]); //=> 0
* R.size([1, 2, 3]); //=> 3
*/
R.size = function _size(list) {
return list.length;
};
/**
* @func
* @memberOf R
* @category List
* @see R.size
*/
R.length = R.size;
/**
* Returns a new list containing only those items that match a given predicate function.
* The predicate function is passed one argument: *(value)*.
*
* Note that `R.filter` does not skip deleted or unassigned indices, unlike the native
* `Array.prototype.filter` method. For more details on this behavior, see:
* https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/filter#Description
*
* @func
* @memberOf R
* @category core
* @category List
* @sig (a -> Boolean) -> [a] -> [a]
* @param {Function} fn The function called per iteration.
* @param {Array} list The collection to iterate over.
* @return {Array} The new filtered array.
* @example
*
* var isEven = function(n) {
* return n % 2 === 0;
* };
* R.filter(isEven, [1, 2, 3, 4]); //=> [2, 4]
*/
var filter = function _filter(fn, list) {
var idx = -1, len = list.length, result = [];
while (++idx < len) {
if (fn(list[idx])) {
result.push(list[idx]);
}
}
return result;
};
R.filter = curry2(checkForMethod('filter', filter));
/**
* Like `filter`, but passes additional parameters to the predicate function. The predicate
* function is passed three arguments: *(value, index, list)*.
*
* @func
* @memberOf R
* @category core
* @category List
* @sig (a, i, [a] -> Boolean) -> [a] -> [a]
* @param {Function} fn The function called per iteration.
* @param {Array} list The collection to iterate over.
* @return {Array} The new filtered array.
* @alias filter.idx
* @example
*
* var lastTwo = function(val, idx, list) {
* return list.length - idx <= 2;
* };
* R.filter.idx(lastTwo, [8, 6, 7, 5, 3, 0, 9]); //=> [0, 9]
*/
function filterIdx(fn, list) {
var idx = -1, len = list.length, result = [];
while (++idx < len) {
if (fn(list[idx], idx, list)) {
result.push(list[idx]);
}
}
return result;
}
R.filter.idx = curry2(filterIdx);
/**
* Similar to `filter`, except that it keeps only values for which the given predicate
* function returns falsy. The predicate function is passed one argument: *(value)*.
*
* @func
* @memberOf R
* @category List
* @sig (a -> Boolean) -> [a] -> [a]
* @param {Function} fn The function called per iteration.
* @param {Array} list The collection to iterate over.
* @return {Array} The new filtered array.
* @example
*
* var isOdd = function(n) {
* return n % 2 === 1;
* };
* R.reject(isOdd, [1, 2, 3, 4]); //=> [2, 4]
*/
var reject = function _reject(fn, list) {
return filter(not(fn), list);
};
R.reject = curry2(reject);
/**
* Like `reject`, but passes additional parameters to the predicate function. The predicate
* function is passed three arguments: *(value, index, list)*.
*
* @func
* @memberOf R
* @category List
* @sig (a, i, [a] -> Boolean) -> [a] -> [a]
* @param {Function} fn The function called per iteration.
* @param {Array} list The collection to iterate over.
* @return {Array} The new filtered array.
* @alias reject.idx
* @example
*
* var lastTwo = function(val, idx, list) {
* return list.length - idx <= 2;
* };
*
* R.reject.idx(lastTwo, [8, 6, 7, 5, 3, 0, 9]); //=> [8, 6, 7, 5, 3]
*/
R.reject.idx = curry2(function _rejectIdx(fn, list) {
return filterIdx(not(fn), list);
});
/**
* Returns a new list containing the first `n` elements of a given list, passing each value
* to the supplied predicate function, and terminating when the predicate function returns
* `false`. Excludes the element that caused the predicate function to fail. The predicate
* function is passed one argument: *(value)*.
*
* @func
* @memberOf R
* @category List
* @sig (a -> Boolean) -> [a] -> [a]
* @param {Function} fn The function called per iteration.
* @param {Array} list The collection to iterate over.
* @return {Array} A new array.
* @example
*
* var isNotFour = function(x) {
* return !(x === 4);
* };
*
* R.takeWhile(isNotFour, [1, 2, 3, 4]); //=> [1, 2, 3]
*/
R.takeWhile = curry2(checkForMethod('takeWhile', function(fn, list) {
var idx = -1, len = list.length;
while (++idx < len && fn(list[idx])) {}
return _slice(list, 0, idx);
}));
/**
* Returns a new list containing the first `n` elements of the given list. If
* `n > * list.length`, returns a list of `list.length` elements.
*
* @func
* @memberOf R
* @category List
* @sig Number -> [a] -> [a]
* @param {number} n The number of elements to return.
* @param {Array} list The array to query.
* @return {Array} A new array containing the first elements of `list`.
*/
R.take = curry2(checkForMethod('take', function(n, list) {
return _slice(list, 0, Math.min(n, list.length));
}));
/**
* Returns a new list containing the last `n` elements of a given list, passing each value
* to the supplied predicate function, beginning when the predicate function returns
* `true`. Excludes the element that caused the predicate function to fail. The predicate
* function is passed one argument: *(value)*.
*
* @func
* @memberOf R
* @category List
* @sig (a -> Boolean) -> [a] -> [a]
* @param {Function} fn The function called per iteration.
* @param {Array} list The collection to iterate over.
* @return {Array} A new array.
* @example
*
* var isTwo = function(x) {
* return x === 2;
* };
*
* R.skipUntil(isTwo, [1, 2, 3, 4]); //=> [2, 3, 4]
*/
R.skipUntil = curry2(function _skipUntil(fn, list) {
var idx = -1, len = list.length;
while (++idx < len && !fn(list[idx])) {}
return _slice(list, idx);
});
/**
* Returns a new list containing all but the first `n` elements of the given `list`.
*
* @func
* @memberOf R
* @category List
* @sig Number -> [a] -> [a]
* @param {number} n The number of elements of `list` to skip.
* @param {Array} list The array to consider.
* @return {Array} The last `n` elements of `list`.
* @example
*
* R.skip(3, [1,2,3,4,5,6,7]); //=> [4,5,6,7]
*/
R.skip = curry2(checkForMethod('skip', function _skip(n, list) {
if (n < list.length) {
return _slice(list, n);
} else {
return [];
}
}));
/**
* Returns the first element of the list which matches the predicate, or `undefined` if no
* element matches.
*
* @func
* @memberOf R
* @category List
* @sig (a -> Boolean) -> [a] -> a | undefined
* @param {Function} fn The predicate function used to determine if the element is the
* desired one.
* @param {Array} list The array to consider.
* @return {Object} The element found, or `undefined`.
* @example
*
* 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
*/
R.find = curry2(function find(fn, list) {
var idx = -1;
var len = list.length;
while (++idx < len) {
if (fn(list[idx])) {
return list[idx];
}
}
});
/**
* Returns the index of the first element of the list which matches the predicate, or `-1`
* if no element matches.
*
* @func
* @memberOf R
* @category List
* @sig (a -> Boolean) -> [a] -> Number
* @param {Function} fn The predicate function used to determine if the element is the
* desired one.
* @param {Array} list The array to consider.
* @return {number} The index of the element found, or `-1`.
* @example
*
* var xs = [{a: 1}, {a: 2}, {a: 3}];
* R.findIndex(R.propEq('a', 2))(xs); //=> 1
* R.findIndex(R.propEq('a', 4))(xs); //=> -1
*/
R.findIndex = curry2(function _findIndex(fn, list) {
var idx = -1;
var len = list.length;
while (++idx < len) {
if (fn(list[idx])) {
return idx;
}
}
return -1;
});
/**
* Returns the last element of the list which matches the predicate, or `undefined` if no
* element matches.
*
* @func
* @memberOf R
* @category List
* @sig (a -> Boolean) -> [a] -> a | undefined
* @param {Function} fn The predicate function used to determine if the element is the
* desired one.
* @param {Array} list The array to consider.
* @return {Object} The element found, or `undefined`.
* @example
*
* 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
*/
R.findLast = curry2(function _findLast(fn, list) {
var idx = list.length;
while (idx--) {
if (fn(list[idx])) {
return list[idx];
}
}
});
/**
* Returns the index of the last element of the list which matches the predicate, or
* `-1` if no element matches.
*
* @func
* @memberOf R
* @category List
* @sig (a -> Boolean) -> [a] -> Number
* @param {Function} fn The predicate function used to determine if the element is the
* desired one.
* @param {Array} list The array to consider.
* @return {number} The index of the element found, or `-1`.
* @example
*
* 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
*/
R.findLastIndex = curry2(function _findLastIndex(fn, list) {
var idx = list.length;
while (idx--) {
if (fn(list[idx])) {
return idx;
}
}
return -1;
});
/**
* Returns `true` if all elements of the list match the predicate, `false` if there are any
* that don't.
*
* @func
* @memberOf R
* @category List
* @sig (a -> Boolean) -> [a] -> Boolean
* @param {Function} fn The predicate function.
* @param {Array} list The array to consider.
* @return {boolean} `true` if the predicate is satisfied by every element, `false`
* otherwise
* @example
*
* var lessThan2 = R.flip(R.lt)(2);
* var lessThan3 = R.flip(R.lt)(3);
* var xs = R.range(1, 3);
* xs; //=> [1, 2]
* R.every(lessThan2)(xs); //=> false
* R.every(lessThan3)(xs); //=> true
*/
function every(fn, list) {
var idx = -1;
while (++idx < list.length) {
if (!fn(list[idx])) {
return false;
}
}
return true;
}
R.every = curry2(every);
/**
* Returns `true` if at least one of elements of the list match the predicate, `false`
* otherwise.
*
* @func
* @memberOf R
* @category List
* @sig (a -> Boolean) -> [a] -> Boolean
* @param {Function} fn The predicate function.
* @param {Array} list The array to consider.
* @return {boolean} `true` if the predicate is satisfied by at least one element, `false`
* otherwise
* @example
*
* var lessThan0 = R.flip(R.lt)(0);
* var lessThan2 = R.flip(R.lt)(2);
* var xs = R.range(1, 3);
* xs; //=> [1, 2]
* R.some(lessThan0)(xs); //=> false
* R.some(lessThan2)(xs); //=> true
*/
function some(fn, list) {
var idx = -1;
while (++idx < list.length) {
if (fn(list[idx])) {
return true;
}
}
return false;
}
R.some = curry2(some);
/**
* Internal implementation of `indexOf`.
* Returns the position of the first occurrence of an item in an array
* (by strict equality),
* or -1 if the item is not included in the array.
*
* @private
* @category Internal
* @param {Array} list The array to search
* @param {*} item the item to find in the Array
* @param {Number} from (optional) the index to start searching the Array
* @return {Number} the index of the found item, or -1
*
*/
var indexOf = function _indexOf(list, item, from) {
var idx = 0, length = list.length;
if (typeof from == 'number') {
idx = from < 0 ? Math.max(0, length + from) : from;
}
for (; idx < length; idx++) {
if (list[idx] === item) {
return idx;
}
}
return -1;
};
/**
* Internal implementation of `lastIndexOf`.
* Returns the position of the last occurrence of an item in an array
* (by strict equality),
* or -1 if the item is not included in the array.
*
* @private
* @category Internal
* @param {Array} list The array to search
* @param {*} item the item to find in the Array
* @param {Number} from (optional) the index to start searching the Array
* @return {Number} the index of the found item, or -1
*
*/
var lastIndexOf = function _lastIndexOf(list, item, from) {
var idx = list.length;
if (typeof from == 'number') {
idx = from < 0 ? idx + from + 1 : Math.min(idx, from + 1);
}
while (--idx >= 0) {
if (list[idx] === item) {
return idx;
}
}
return -1;
};
/**
* Returns the position of the first occurrence of an item in an array
* (by strict equality),
* or -1 if the item is not included in the array.
*
* @func
* @memberOf R
* @category List
* @sig a -> [a] -> Number
* @param {*} target The item to find.
* @param {Array} list The array to search in.
* @return {Number} the index of the target, or -1 if the target is not found.
*
* @example
*
* R.indexOf(3, [1,2,3,4]); //=> 2
* R.indexOf(10, [1,2,3,4]); //=> -1
*/
R.indexOf = curry2(function _indexOf(target, list) {
return indexOf(list, target);
});
/**
* Returns the position of the first occurrence of an item (by strict equality) in
* an array, or -1 if the item is not included in the array. However,
* `indexOf.from` will only search the tail of the array, starting from the
* `fromIdx` parameter.
*
* @func
* @memberOf R
* @category List
* @sig a -> Number -> [a] -> Number
* @param {*} target The item to find.
* @param {Array} list The array to search in.
* @param {Number} fromIdx the index to start searching from
* @return {Number} the index of the target, or -1 if the target is not found.
*
* @example
*
* R.indexOf.from(3, 2, [-1,0,1,2,3,4]); //=> 4
* R.indexOf.from(10, 2, [1,2,3,4]); //=> -1
*/
R.indexOf.from = curry3(function indexOfFrom(target, fromIdx, list) {
return indexOf(list, target, fromIdx);
});
/**
* Returns the position of the last occurrence of an item (by strict equality) in
* an array, or -1 if the item is not included in the array.
*
* @func
* @memberOf R
* @category List
* @sig a -> [a] -> Number
* @param {*} target The item to find.
* @param {Array} list The array to search in.
* @return {Number} the index of the target, or -1 if the target is not found.
*
* @example
*
* R.lastIndexOf(3, [-1,3,3,0,1,2,3,4]); //=> 6
* R.lastIndexOf(10, [1,2,3,4]); //=> -1
*/
R.lastIndexOf = curry2(function _lastIndexOf(target, list) {
return lastIndexOf(list, target);
});
/**
* Returns the position of the last occurrence of an item (by strict equality) in
* an array, or -1 if the item is not included in the array. However,
* `lastIndexOf.from` will only search the tail of the array, starting from the
* `fromIdx` parameter.
*
* @func
* @memberOf R
* @category List
* @sig a -> Number -> [a] -> Number
* @param {*} target The item to find.
* @param {Array} list The array to search in.
* @param {Number} fromIdx the index to start searching from
* @return {Number} the index of the target, or -1 if the target is not found.
*
* @example
*
* R.lastIndexOf.from(3, 2, [-1,3,3,0,1,2,3,4]); //=> 2
* R.lastIndexOf.from(10, 2, [1,2,3,4]); //=> -1
*/
R.lastIndexOf.from = curry3(function lastIndexOfFrom(target, fromIdx, list) {
return lastIndexOf(list, target, fromIdx);
});
/**
* Returns `true` if the specified item is somewhere in the list, `false` otherwise.
* Equivalent to `indexOf(a)(list) > -1`. Uses strict (`===`) equality checking.
*
* @func
* @memberOf R
* @category List
* @sig a -> [a] -> Boolean
* @param {Object} a The item to compare against.
* @param {Array} list The array to consider.
* @return {boolean} `true` if the item is in the list, `false` otherwise.
* @example
*
* R.contains(3)([1, 2, 3]); //=> true
* R.contains(4)([1, 2, 3]); //=> false
* R.contains({})([{}, {}]); //=> false
* var obj = {};
* R.contains(obj)([{}, obj, {}]); //=> true
*/
function contains(a, list) {
return indexOf(list, a) > -1;
}
R.contains = curry2(contains);
/**
* Returns `true` if the `x` is found in the `list`, using `pred` as an
* equality predicate for `x`.
*
* @func
* @memberOf R
* @category List
* @sig (x, a -> Boolean) -> x -> [a] -> Boolean
* @param {Function} pred A predicate used to test whether two items are equal.
* @param {*} x The item to find
* @param {Array} list The list to iterate over
* @return {Boolean} `true` if `x` is in `list`, else `false`
* @example
*
* var xs = [{x: 12}, {x: 11}, {x: 10}];
* R.containsWith(function(a, b) { return a.x === b.x; }, {x: 10}, xs); //=> true
* R.containsWith(function(a, b) { return a.x === b.x; }, {x: 1}, xs); //=> false
*/
function containsWith(pred, x, list) {
var idx = -1, len = list.length;
while (++idx < len) {
if (pred(x, list[idx])) {
return true;
}
}
return false;
}
R.containsWith = curry3(containsWith);
/**
* Returns a new list containing only one copy of each element in the original list.
* Equality is strict here, meaning reference equality for objects and non-coercing equality
* for primitives.
*
* @func
* @memberOf R
* @category List
* @sig [a] -> [a]
* @param {Array} list The array to consider.
* @return {Array} The list of unique items.
* @example
*
* R.uniq([1, 1, 2, 1]); //=> [1, 2]
* R.uniq([{}, {}]); //=> [{}, {}]
* R.uniq([1, '1']); //=> [1, '1']
*/
var uniq = R.uniq = function uniq(list) {
var idx = -1, len = list.length;
var result = [], item;
while (++idx < len) {
item = list[idx];
if (!contains(item, result)) {
result.push(item);
}
}
return result;
};
/**
* Returns `true` if all elements are unique, otherwise `false`.
* Uniqueness is determined using strict equality (`===`).
*
* @func
* @memberOf R
* @category List
* @sig [a] -> Boolean
* @param {Array} list The array to consider.
* @return {boolean} `true` if all elements are unique, else `false`.
* @example
*
* R.isSet(['1', 1]); //=> true
* R.isSet([1, 1]); //=> false
* R.isSet([{}, {}]); //=> true
*/
R.isSet = function _isSet(list) {
var len = list.length;
var idx = -1;
while (++idx < len) {
if (indexOf(list, list[idx], idx + 1) >= 0) {
return false;
}
}
return true;
};
/**
* Returns a new list containing only one copy of each element in the original list, based
* upon the value returned by applying the supplied predicate to two list elements. Prefers
* the first item if two items compare equal based on the predicate.
*
* @func
* @memberOf R
* @category List
* @sig (x, a -> Boolean) -> [a] -> [a]
* @param {Function} pred A predicate used to test whether two items are equal.
* @param {Array} list The array to consider.
* @return {Array} The list of unique items.
* @example
*
* var strEq = function(a, b) { return ('' + a) === ('' + b) };
* R.uniqWith(strEq)([1, '1', 2, 1]); //=> [1, 2]
* R.uniqWith(strEq)([{}, {}]); //=> [{}]
* R.uniqWith(strEq)([1, '1', 1]); //=> [1]
* R.uniqWith(strEq)(['1', 1, 1]); //=> ['1']
*/
var uniqWith = R.uniqWith = curry2(function _uniqWith(pred, list) {
var idx = -1, len = list.length;
var result = [], item;
while (++idx < len) {
item = list[idx];
if (!containsWith(pred, item, result)) {
result.push(item);
}
}
return result;
});
/**
* Returns a new list by plucking the same named property off all objects in the list supplied.
*
* @func
* @memberOf R
* @category List
* @sig String -> {*} -> [*]
* @param {string|number} key The key name to pluck off of each object.
* @param {Array} list The array to consider.
* @return {Array} The list of values for the given key.
* @example
*
* R.pluck('a')([{a: 1}, {a: 2}]); //=> [1, 2]
* R.pluck(0)([[1, 2], [3, 4]]); //=> [1, 3]
*/
var pluck = R.pluck = curry2(function _pluck(p, list) {
return map(prop(p), list);
});
/**
* `makeFlat` is a helper function that returns a one-level or fully recursive function
* based on the flag passed in.
*
* @private
*/
// TODO: document, even for internals...
var makeFlat = function _makeFlat(recursive) {
return function __flatt(list) {
var value, result = [], idx = -1, j, ilen = list.length, jlen;
while (++idx < ilen) {
if (R.isArrayLike(list[idx])) {
value = (recursive) ? __flatt(list[idx]) : list[idx];
j = -1;
jlen = value.length;
while (++j < jlen) {
result.push(value[j]);
}
} else {
result.push(list[idx]);
}
}
return result;
};
};
/**
* Returns a new list by pulling every item out of it (and all its sub-arrays) and putting
* them in a new array, depth-first.
*
* @func
* @memberOf R
* @category List
* @sig [a] -> [b]
* @param {Array} list The array to consider.
* @return {Array} The flattened list.
* @example
*
* 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]
*/
R.flatten = makeFlat(true);
/**
* Returns a new list by pulling every item at the first level of nesting out, and putting
* them in a new array.
*
* @func
* @memberOf R
* @category List
* @sig [a] -> [b]
* @param {Array} list The array to consider.
* @return {Array} The flattened list.
* @example
*
* R.unnest([1, [2], [[3]]]); //=> [1, 2, [3]]
* R.unnest([[1, 2], [3, 4], [5, 6]]); //=> [1, 2, 3, 4, 5, 6]
*/
var unnest = R.unnest = makeFlat(false);
/**
* Creates a new list out of the two supplied by applying the function to
* each equally-positioned pair in the lists. The returned list is
* truncated to the length of the shorter of the two input lists.
*
* @function
* @memberOf R
* @category List
* @sig (a,b -> c) -> a -> b -> [c]
* @param {Function} fn The function used to combine the two elements into one value.
* @param {Array} list1 The first array to consider.
* @param {Array} list2 The second array to consider.
* @return {Array} The list made by combining same-indexed elements of `list1` and `list2`
* using `fn`.
* @example
*
* var f = function(x, y) {
* // ...
* };
* R.zipWith(f, [1, 2, 3], ['a', 'b', 'c']);
* //=> [f(1, 'a'), f(2, 'b'), f(3, 'c')]
*/
R.zipWith = curry3(function _zipWith(fn, a, b) {
var rv = [], idx = -1, len = Math.min(a.length, b.length);
while (++idx < len) {
rv[idx] = fn(a[idx], b[idx]);
}
return rv;
});
/**
* Creates a new list out of the two supplied by pairing up
* equally-positioned items from both lists. The returned list is
* truncated to the length of the shorter of the two input lists.
* Note: `zip` is equivalent to `zipWith(function(a, b) { return [a, b] })`.
*
* @func
* @memberOf R
* @category List
* @sig a -> b -> [[a,b]]
* @param {Array} list1 The first array to consider.
* @param {Array} list2 The second array to consider.
* @return {Array} The list made by pairing up same-indexed elements of `list1` and `list2`.
* @example
*
* R.zip([1, 2, 3], ['a', 'b', 'c']); //=> [[1, 'a'], [2, 'b'], [3, 'c']]
*/
R.zip = curry2(function _zip(a, b) {
var rv = [];
var idx = -1;
var len = Math.min(a.length, b.length);
while (++idx < len) {
rv[idx] = [a[idx], b[idx]];
}
return rv;
});
/**
* Creates a new object out of a list of keys and a list of values.
*
* @func
* @memberOf R
* @category List
* @sig k -> v -> {k: v}
* @param {Array} keys The array that will be properties on the output object.
* @param {Array} values The list of values on the output object.
* @return {Object} The object made by pairing up same-indexed elements of `keys` and `values`.
* @example
*
* R.zipObj(['a', 'b', 'c'], [1, 2, 3]); //=> {a: 1, b: 2, c: 3}
*/
R.zipObj = curry2(function _zipObj(keys, values) {
var idx = -1, len = keys.length, out = {};
while (++idx < len) {
out[keys[idx]] = values[idx];
}
return out;
});
/**
* Creates a new object out of a list key-value pairs.
*
* @func
* @memberOf R
* @category List
* @sig [[k,v]] -> {k: v}
* @param {Array} pairs An array of two-element arrays that will be the keys and values of the output object.
* @return {Object} The object made by pairing up `keys` and `values`.
* @example
*
* R.fromPairs([['a', 1], ['b', 2], ['c', 3]]); //=> {a: 1, b: 2, c: 3}
*/
R.fromPairs = function _fromPairs(pairs) {
var idx = -1, len = pairs.length, out = {};
while (++idx < len) {
if (isArray(pairs[idx]) && pairs[idx].length) {
out[pairs[idx][0]] = pairs[idx][1];
}
}
return out;
};
/**
* Creates an object containing a single key:value pair.
*
* @func
* @memberOf R
* @category Object
* @sig String -> a -> {String:a}
* @param {String} key
* @param {*} val
* @return {Object}
* @example
*
* var matchPhrases = R.compose(
* R.createMapEntry('must'),
* R.map(R.createMapEntry('match_phrase'))
* );
* matchPhrases(['foo', 'bar', 'baz']); //=> {must: [{match_phrase: 'foo'}, {match_phrase: 'bar'}, {match_phrase: 'baz'}]}
*/
R.createMapEntry = curry2(function(key, val) {
var obj = {};
obj[key] = val;
return obj;
});
/**
* Creates a new list out of the two supplied by applying the function
* to each possible pair in the lists.
*
* @see R.xprod
* @func
* @memberOf R
* @category List
* @sig (a,b -> c) -> a -> b -> [c]
* @param {Function} fn The function to join pairs with.
* @param {Array} as The first list.
* @param {Array} bs The second list.
* @return {Array} The list made by combining each possible pair from
* `as` and `bs` using `fn`.
* @example
*
* var f = function(x, y) {
* // ...
* };
* R.xprodWith(f, [1, 2], ['a', 'b']);
* // [f(1, 'a'), f(1, 'b'), f(2, 'a'), f(2, 'b')];
*/
R.xprodWith = curry3(function _xprodWith(fn, a, b) {
if (isEmpty(a) || isEmpty(b)) {
return [];
}
// Better to push them all or to do `new Array(ilen * jlen)` and
// calculate indices?
var idx = -1, ilen = a.length, j, jlen = b.length, result = [];
while (++idx < ilen) {
j = -1;
while (++j < jlen) {
result.push(fn(a[idx], b[j]));
}
}
return result;
});
/**
* Creates a new list out of the two supplied by creating each possible
* pair from the lists.
*
* @func
* @memberOf R
* @category List
* @sig a -> b -> [[a,b]]
* @param {Array} as The first list.
* @param {Array} bs The second list.
* @return {Array} The list made by combining each possible pair from
* `as` and `bs` into pairs (`[a, b]`).
* @example
*
* R.xprod([1, 2], ['a', 'b']); //=> [[1, 'a'], [1, 'b'], [2, 'a'], [2, 'b']]
*/
R.xprod = curry2(function _xprod(a, b) { // = xprodWith(prepend); (takes about 3 times as long...)
if (isEmpty(a) || isEmpty(b)) {
return [];
}
var idx = -1;
var ilen = a.length;
var j;
var jlen = b.length;
// Better to push them all or to do `new Array(ilen * jlen)` and calculate indices?
var result = [];
while (++idx < ilen) {
j = -1;
while (++j < jlen) {
result.push([a[idx], b[j]]);
}
}
return result;
});
/**
* Returns a new list with the same elements as the original list, just
* in the reverse order.
*
* @func
* @memberOf R
* @category List
* @sig [a] -> [a]
* @param {Array} list The list to reverse.
* @return {Array} A copy of the list in reverse order.
* @example
*
* R.reverse([1, 2, 3]); //=> [3, 2, 1]
* R.reverse([1, 2]); //=> [2, 1]
* R.reverse([1]); //=> [1]
* R.reverse([]); //=> []
*/
R.reverse = function reverse(list) {
var idx = -1, length = list.length;
var pointer = length;
var result = new Array(length);
while (++idx < length) {
result[--pointer] = list[idx];
}
return result;
};
/**
* Returns a list of numbers from `from` (inclusive) to `to`
* (exclusive).
*
* @func
* @memberOf R
* @category List
* @sig Number -> Number -> [Number]
* @param {number} from The first number in the list.
* @param {number} to One more than the last number in the list.
* @return {Array} The list of numbers in tthe set `[a, b)`.
* @example
*
* R.range(1, 5); //=> [1, 2, 3, 4]
* R.range(50, 53); //=> [50, 51, 52]
*/
R.range = curry2(function _range(from, to) {
if (from >= to) {
return [];
}
var idx = 0, result = new Array(Math.floor(to) - Math.ceil(from));
for (; from < to; idx++, from++) {
result[idx] = from;
}
return result;
});
/**
* Returns a string made by inserting the `separator` between each
* element and concatenating all the elements into a single string.
*
* @func
* @memberOf R
* @category List
* @sig String -> [a] -> String
* @param {string|number} separator The string used to separate the elements.
* @param {Array} xs The elements to join into a string.
* @return {string} str The string made by concatenating `xs` with `separator`.
* @example
*
* var spacer = R.join(' ');
* spacer(['a', 2, 3.4]); //=> 'a 2 3.4'
* R.join('|', [1, 2, 3]); //=> '1|2|3'
*/
R.join = invoker(Array.prototype.join);
/**
* Returns the elements from `xs` starting at `a` and ending at `b - 1`.
*
* @func
* @memberOf R
* @category List
* @sig Number -> Number -> [a] -> [a]
* @param {number} a The starting index.
* @param {number} b One more than the ending index.
* @param {Array} xs The list to take elements from.
* @return {Array} The items from `a` to `b - 1` from `xs`.
* @example
*
* var xs = R.range(0, 10);
* R.slice(2, 5)(xs); //=> [2, 3, 4]
*/
R.slice = invoker(Array.prototype.slice);
/**
* Returns the elements from `xs` starting at `a` going to the end of `xs`.
*
* @func
* @memberOf R
* @category List
* @sig Number -> [a] -> [a]
* @param {number} a The starting index.
* @param {Array} xs The list to take elements from.
* @return {Array} The items from `a` to the end of `xs`.
* @example
*
* var xs = R.range(0, 10);
* R.slice.from(2)(xs); //=> [2, 3, 4, 5, 6, 7, 8, 9]
*
* var ys = R.range(4, 8);
* var tail = R.slice.from(1);
* tail(ys); //=> [5, 6, 7]
*/
R.slice.from = curry2(function(a, xs) {
return xs.slice(a, xs.length);
});
/**
* Removes the sub-list of `list` starting at index `start` and containing
* `count` elements. _Note that this is not destructive_: it returns a
* copy of the list with the changes.
* <small>No lists have been harmed in the application of this function.</small>
*
* @func
* @memberOf R
* @category List
* @sig Number -> Number -> [a] -> [a]
* @param {Number} start The position to start removing elements
* @param {Number} count The number of elements to remove
* @param {Array} list The list to remove from
* @return {Array} a new Array with `count` elements from `start` removed
* @example
*
* R.remove(2, 3, [1,2,3,4,5,6,7,8]); //=> [1,2,6,7,8]
*/
R.remove = curry3(function _remove(start, count, list) {
return concat(_slice(list, 0, Math.min(start, list.length)), _slice(list, Math.min(list.length, start + count)));
});
/**
* Inserts the supplied element into the list, at index `index`. _Note
* that this is not destructive_: it returns a copy of the list with the changes.
* <small>No lists have been harmed in the application of this function.</small>
*
* @func
* @memberOf R
* @category List
* @sig Number -> a -> [a] -> [a]
* @param {Number} index The position to insert the element
* @param {*} elt The element to insert into the Array
* @param {Array} list The list to insert into
* @return {Array} a new Array with `elt` inserted at `index`
* @example
*
* R.insert(2, 'x', [1,2,3,4]); //=> [1,2,'x',3,4]
*/
R.insert = curry3(function _insert(idx, elt, list) {
idx = idx < list.length && idx >= 0 ? idx : list.length;
return concat(append(elt, _slice(list, 0, idx)), _slice(list, idx));
});
/**
* Inserts the sub-list into the list, at index `index`. _Note that this
* is not destructive_: it returns a copy of the list with the changes.
* <small>No lists have been harmed in the application of this function.</small>
*
* @func
* @memberOf R
* @category List
* @sig Number -> [a] -> [a] -> [a]
* @param {Number} index The position to insert the sub-list
* @param {Array} elts The sub-list to insert into the Array
* @param {Array} list The list to insert the sub-list into
* @return {Array} a new Array with `elts` inserted starting at `index`
* @example
*
* R.insert.all(2, ['x','y','z'], [1,2,3,4]); //=> [1,2,'x','y','z',3,4]
*/
R.insert.all = curry3(function _insertAll(idx, elts, list) {
idx = idx < list.length && idx >= 0 ? idx : list.length;
return concat(concat(_slice(list, 0, idx), elts), _slice(list, idx));
});
/**
* Makes a comparator function out of a function that reports whether the first element is less than the second.
*
* @func
* @memberOf R
* @category Function
* @sig (a, b -> Boolean) -> (a, b -> Number)
* @param {Function} pred A predicate function of arity two.
* @return {Function} a Function :: a -> b -> Int that returns `-1` if a < b, `1` if b < a, otherwise `0`
* @example
*
* var cmp = R.comparator(function(a, b) {
* return a.age < b.age;
* });
* var people = [
* // ...
* ];
* R.sort(cmp, people);
*/
var comparator = R.comparator = function _comparator(pred) {
return function(a, b) {
return pred(a, b) ? -1 : pred(b, a) ? 1 : 0;
};
};
/**
* Returns a copy of the list, sorted according to the comparator function, which should accept two values at a
* time and return a negative number if the first value is smaller, a positive number if it's larger, and zero
* if they are equal. Please note that this is a **copy** of the list. It does not modify the original.
*
* @func
* @memberOf R
* @category List
* @sig (a,a -> Number) -> [a] -> [a]
* @param {Function} comparator A sorting function :: a -> b -> Int
* @param {Array} list The list to sort
* @return {Array} a new array with its elements sorted by the comparator function.
* @example
*
* var diff = function(a, b) { return a - b; };
* R.sort(diff, [4,2,7,5]); //=> [2, 4, 5, 7]
*/
R.sort = curry2(function sort(comparator, list) {
return clone(list).sort(comparator);
});
/**
* 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.
*
* @func
* @memberOf R
* @category List
* @sig (a -> s) -> [a] -> {s: a}
* @param {Function} fn Function :: a -> String
* @param {Array} list The array to group
* @return {Object} An object with the output of `fn` for keys, mapped to arrays of elements
* that produced that key when passed to `fn`.
* @example
*
* 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}]
* // }
*/
R.groupBy = curry2(function _groupBy(fn, list) {
return foldl(function(acc, elt) {
var key = fn(elt);
acc[key] = append(elt, acc[key] || (acc[key] = []));
return acc;
}, {}, list);
});
/**
* Takes a predicate and a list and returns the pair of lists of
* elements which do and do not satisfy the predicate, respectively.
*
* @func
* @memberOf R
* @category List
* @sig (a -> Boolean) -> [a] -> [[a],[a]]
* @param {Function} pred A predicate to determine which array the element belongs to.
* @param {Array} list The array to partition.
* @return {Array} A nested array, containing first an array of elements that satisfied the predicate,
* and second an array of elements that did not satisfy.
* @example
*
* R.partition(R.contains('s'), ['sss', 'ttt', 'foo', 'bars']);
* //=> [ [ 'sss', 'bars' ], [ 'ttt', 'foo' ] ]
*/
R.partition = curry2(function _partition(pred, list) {
return foldl(function(acc, elt) {
acc[pred(elt) ? 0 : 1].push(elt);
return acc;
}, [[], []], list);
});
// Object Functions
// ----------------
//
// These functions operate on plain Javascript object, adding simple functions to test properties on these
// objects. Many of these are of most use in conjunction with the list functions, operating on lists of
// objects.
// --------
/**
* Runs the given function with the supplied object, then returns the object.
*
* @func
* @memberOf R
* @category Function
* @sig (a -> *) -> a -> a
* @param {Function} fn The function to call with `x`. The return value of `fn` will be thrown away.
* @param {*} x
* @return {*} x
* @example
*
* var sayX = function(x) { console.log('x is ' + x); };
* R.tap(sayX, 100); //=> 100
* //-> 'x is 100')
*/
R.tap = curry2(function _tap(fn, x) {
fn(x);
return x;
});
/**
* Tests if two items are equal. Equality is strict here, meaning reference equality for objects and
* non-coercing equality for primitives.
*
* @func
* @memberOf R
* @category Relation
* @sig a -> b -> Boolean
* @param {*} a
* @param {*} b
* @return {Boolean}
* @example
*
* var o = {};
* R.eq(o, o); //=> true
* R.eq(o, {}); //=> false
* R.eq(1, 1); //=> true
* R.eq(1, '1'); //=> false
*/
R.eq = curry2(function _eq(a, b) { return a === b; });
/**
* Returns a function that when supplied an object returns the indicated property of that object, if it exists.
*
* @func
* @memberOf R
* @category Object
* @sig s -> {s: a} -> a
* @param {String} p The property name
* @param {Object} obj The object to query
* @return {*} The value at obj.p
* @example
*
* R.prop('x', {x: 100}); //=> 100
* R.prop('x', {}); //=> undefined
*
* var fifth = R.prop(4); // indexed from 0, remember
* fifth(['Bashful', 'Doc', 'Dopey', 'Grumpy', 'Happy', 'Sleepy', 'Sneezy']);
* //=> 'Happy'
*/
var prop = R.prop = function prop(p, obj) {
switch (arguments.length) {
case 0: throw noArgsException();
case 1: return function _prop(obj) { return obj[p]; };
}
return obj[p];
};
/**
* @func
* @memberOf R
* @category Object
* @see R.prop
*/
R.get = R.prop;
/**
* Returns the value at the specified property.
* The only difference from `prop` is the parameter order.
*
* @func
* @memberOf R
* @see R.prop
* @category Object
* @sig {s: a} -> s -> a
* @param {Object} obj The object to query
* @param {String} prop The property name
* @return {*} The value at obj.p
* @example
*
* R.props({x: 100}, 'x'); //=> 100
*/
R.props = flip(R.prop);
/**
* An internal reference to `Object.prototype.hasOwnProperty`
* @private
*/
var hasOwnProperty = Object.prototype.hasOwnProperty;
/**
* If the given object has an own property with the specified name,
* returns the value of that property.
* Otherwise returns the provided default value.
*
* @func
* @memberOf R
* @category Object
* @sig s -> v -> {s: x} -> x | v
* @param {String} p The name of the property to return.
* @param {*} val The default value.
* @param {Object} obj The object to query.
* @returns {*} The value of given property or default value.
* @example
*
* var alice = {
* name: 'ALICE',
* age: 101
* };
* var favorite = R.prop('favoriteLibrary');
* var favoriteWithDefault = R.propOr('favoriteLibrary', 'Ramda');
*
* favorite(alice); //=> undefined
* favoriteWithDefault(alice); //=> 'Ramda'
*/
R.propOr = curry3(function _propOr(p, val, obj) {
return hasOwnProperty.call(obj, p) ? obj[p] : val;
});
/**
* Returns whether or not an object has an own property with
* the specified name
*
* @func
* @memberOf R
* @category Object
* @sig s -> {s: x} -> Boolean
* @param {String} prop The name of the property to check for.
* @param {Object} obj The object to query.
* @return {Boolean} Whether the property exists.
* @example
*
* var obj = {
* foo: 1,
* bar: 2,
* };
* R.has('foo', obj); //=> true
*
* var list = [{foo: 1}, {foo: 2}, {bar: 3}];
* R.filter(R.has('foo'), list); //=> [{foo: 1}, {foo: 2}]
*/
R.has = curry2(function(prop, obj) {
return hasOwnProperty.call(obj, prop);
});
/**
* Returns whether or not an object or its prototype chain has
* a property with the specified name
*
* @func
* @memberOf R
* @category Object
* @sig s -> {s: x} -> Boolean
* @param {String} prop The name of the property to check for.
* @param {Object} obj The object to query.
* @return {Boolean} Whether the property exists.
* @example
*
* 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
*/
R.hasIn = curry2(function(prop, obj) {
return prop in obj;
});
/**
* Calls the specified function on the supplied object. Any additional arguments
* after `fn` and `obj` are passed in to `fn`. If no additional arguments are passed to `func`,
* `fn` is invoked with no arguments.
*
* @func
* @memberOf R
* @category Object
* @sig k -> {k : v} -> v(*)
* @param {String} funcName The name of the property mapped to the function to invoke
* @param {Object} obj The object
* @return {*} The value of invoking `obj.fn`
* @example
*
* R.func('add', R, 1, 2); //=> 3
*
* var obj = { f: function() { return 'f called'; } };
* R.func('f', obj); //=> 'f called'
*/
R.func = function _func(funcName, obj) {
switch (arguments.length) {
case 0: throw noArgsException();
case 1: return function(obj) { return obj[funcName].apply(obj, _slice(arguments, 1)); };
default: return obj[funcName].apply(obj, _slice(arguments, 2));
}
};
/**
* Returns a function that always returns the given value.
*
* @func
* @memberOf R
* @category Function
* @sig a -> (* -> a)
* @param {*} val The value to wrap in a function
* @return {Function} A Function :: * -> val
* @example
*
* var t = R.always('Tee');
* t(); //=> 'Tee'
*/
var always = R.always = function _always(val) {
return function() {
return val;
};
};
/**
* Internal reference to Object.keys
*
* @private
* @param {Object}
* @return {Array}
*/
var nativeKeys = Object.keys;
/**
* Creates a function that is bound to a context.
* Note: `R.bind` does not provide the additional argument-binding capabilities of
* [Function.prototype.bind](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/bind).
*
* @func
* @memberOf R
* @category Function
* @category Object
* @sig (* -> *) -> {*} -> (* -> *)
* @param {Function} fn The function to bind to context
* @param {Object} thisObj The context to bind `fn` to
* @return {Function} A function that will execute in the context of `thisObj`
*/
R.bind = curry2(function bind(fn, thisObj) {
return function() {
return fn.apply(thisObj, arguments);
};
});
/**
* Returns a list containing the names of all the enumerable own
* properties of the supplied object.
* Note that the order of the output array is not guaranteed to be
* consistent across different JS platforms.
*
* @func
* @memberOf R
* @category Object
* @sig {k: v} -> [k]
* @param {Object} obj The object to extract properties from
* @return {Array} An array of the object's own properties
* @example
*
* R.keys({a: 1, b: 2, c: 3}); //=> ['a', 'b', 'c']
*/
var keys = R.keys = (function() {
// cover IE < 9 keys issues
var hasEnumBug = !({toString: null}).propertyIsEnumerable('toString');
var nonEnumerableProps = ['constructor', 'valueOf', 'isPrototypeOf', 'toString',
'propertyIsEnumerable', 'hasOwnProperty', 'toLocaleString'];
return function _keys(obj) {
if (Object(obj) !== obj) {
return [];
}
if (nativeKeys) {
return nativeKeys(obj);
}
var prop, ks = [], nIdx;
for (prop in obj) {
if (hasOwnProperty.call(obj, prop)) {
ks.push(prop);
}
}
if (hasEnumBug) {
nIdx = nonEnumerableProps.length;
while (nIdx--) {
prop = nonEnumerableProps[nIdx];
if (hasOwnProperty.call(obj, prop) && !R.contains(prop, ks)) {
ks.push(prop);
}
}
}
return ks;
};
}());
/**
* Returns a list containing the names of all the
* properties of the supplied object, including prototype properties.
* Note that the order of the output array is not guaranteed to be
* consistent across different JS platforms.
*
* @func
* @memberOf R
* @category Object
* @sig {k: v} -> [k]
* @param {Object} obj The object to extract properties from
* @return {Array} An array of the object's own and prototype properties
* @example
*
* var F = function() { this.x = 'X'; };
* F.prototype.y = 'Y';
* var f = new F();
* R.keysIn(f); //=> ['x', 'y']
*/
var keysIn = R.keysIn = function _keysIn(obj) {
var prop, ks = [];
for (prop in obj) {
ks.push(prop);
}
return ks;
};
/**
* @private
* @param {Function} fn The strategy for extracting keys from an object
* @return {Function} A function that takes an object and returns an array of
* key-value arrays.
*/
var pairWith = function(fn) {
return function(obj) {
return R.map(function(key) { return [key, obj[key]]; }, fn(obj));
};
};
/**
* Converts an object into an array of key, value arrays.
* Only the object's own properties are used.
* Note that the order of the output array is not guaranteed to be
* consistent across different JS platforms.
*
* @func
* @memberOf R
* @category Object
* @sig {k: v} -> [[k,v]]
* @param {Object} obj The object to extract from
* @return {Array} An array of key, value arrays from the object's own properties
* @example
*
* R.toPairs({a: 1, b: 2, c: 3}); //=> [['a', 1], ['b', 2], ['c', 3]]
*/
R.toPairs = pairWith(R.keys);
/**
* Converts an object into an array of key, value arrays.
* The object's own properties and prototype properties are used.
* Note that the order of the output array is not guaranteed to be
* consistent across different JS platforms.
*
* @func
* @memberOf R
* @category Object
* @sig {k: v} -> [[k,v]]
* @param {Object} obj The object to extract from
* @return {Array} An array of key, value arrays from the object's own
* and prototype properties
* @example
*
* var F = function() { this.x = 'X'; };
* F.prototype.y = 'Y';
* var f = new F();
* R.toPairsIn(f); //=> [['x','X'], ['y','Y']]
*/
R.toPairsIn = pairWith(R.keysIn);
/**
* Returns a list of all the enumerable own properties of the supplied object.
* Note that the order of the output array is not guaranteed across
* different JS platforms.
*
* @func
* @memberOf R
* @category Object
* @sig {k: v} -> [v]
* @param {Object} obj The object to extract values from
* @return {Array} An array of the values of the object's own properties
* @example
*
* R.values({a: 1, b: 2, c: 3}); //=> [1, 2, 3]
*/
R.values = function _values(obj) {
var props = keys(obj),
length = props.length,
vals = new Array(length);
for (var idx = 0; idx < length; idx++) {
vals[idx] = obj[props[idx]];
}
return vals;
};
/**
* Returns a list of all the properties, including prototype properties,
* of the supplied object.
* Note that the order of the output array is not guaranteed to be
* consistent across different JS platforms.
*
* @func
* @memberOf R
* @category Object
* @sig {k: v} -> [v]
* @param {Object} obj The object to extract values from
* @return {Array} An array of the values of the object's own and prototype properties
* @example
*
* var F = function() { this.x = 'X'; };
* F.prototype.y = 'Y';
* var f = new F();
* R.valuesIn(f); //=> ['X', 'Y']
*/
R.valuesIn = function _valuesIn(obj) {
var prop, vs = [];
for (prop in obj) {
vs.push(obj[prop]);
}
return vs;
};
/**
* Internal helper function for making a partial copy of an object
*
* @private
*
*/
// TODO: document, even for internals...
function pickWith(test, obj) {
var copy = {},
props = keysIn(obj), prop, val;
for (var idx = 0, len = props.length; idx < len; idx++) {
prop = props[idx];
val = obj[prop];
if (test(val, prop, obj)) {
copy[prop] = val;
}
}
return copy;
}
/**
* Returns a partial copy of an object containing only the keys specified. If the key does not exist, the
* property is ignored.
*
* @func
* @memberOf R
* @category Object
* @sig [k] -> {k: v} -> {k: v}
* @param {Array} names an array of String property names to copy onto a new object
* @param {Object} obj The object to copy from
* @return {Object} A new object with only properties from `names` on it.
* @example
*
* 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}
*/
R.pick = curry2(function pick(names, obj) {
return pickWith(function(val, key) {
return contains(key, names);
}, obj);
});
/**
* Returns a partial copy of an object omitting the keys specified.
*
* @func
* @memberOf R
* @category Object
* @sig [k] -> {k: v} -> {k: v}
* @param {Array} names an array of String property names to omit from the new object
* @param {Object} obj The object to copy from
* @return {Object} A new object with properties from `names` not on it.
* @example
*
* R.omit(['a', 'd'], {a: 1, b: 2, c: 3, d: 4}); //=> {b: 2, c: 3}
*/
R.omit = curry2(function omit(names, obj) {
return pickWith(function(val, key) {
return !contains(key, names);
}, obj);
});
/**
* Returns a partial copy of an object containing only the keys that
* satisfy the supplied predicate.
*
* @func
* @memberOf R
* @category Object
* @sig (v, k -> Boolean) -> {k: v} -> {k: v}
* @param {Function} pred A predicate to determine whether or not a key
* should be included on the output object.
* @param {Object} obj The object to copy from
* @return {Object} A new object with only properties that satisfy `pred`
* on it.
* @see R.pick
* @example
*
* var isUpperCase = function(val, key) { return key.toUpperCase() === key; }
* R.pickWith(isUpperCase, {a: 1, b: 2, A: 3, B: 4}); //=> {A: 3, B: 4}
*/
R.pickWith = curry2(pickWith);
/**
* Internal implementation of `pickAll`
*
* @private
* @see R.pickAll
*/
// TODO: document, even for internals...
var pickAll = function _pickAll(names, obj) {
var copy = {};
forEach(function(name) {
copy[name] = obj[name];
}, names);
return copy;
};
/**
* Similar to `pick` except that this one includes a `key: undefined` pair for properties that don't exist.
*
* @func
* @memberOf R
* @category Object
* @sig [k] -> {k: v} -> {k: v}
* @param {Array} names an array of String property names to copy onto a new object
* @param {Object} obj The object to copy from
* @return {Object} A new object with only properties from `names` on it.
* @see R.pick
* @example
*
* 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}
*/
R.pickAll = curry2(pickAll);
/**
* Assigns own enumerable properties of the other object to the destination
* object preferring items in other.
*
* @private
* @memberOf R
* @category Object
* @param {Object} destination The destination object.
* @param {Object} other The other object to merge with destination.
* @returns {Object} Returns the destination object.
* @example
*
* extend({ 'name': 'fred', 'age': 10 }, { 'age': 40 });
* //=> { 'name': 'fred', 'age': 40 }
*/
function extend(destination, other) {
var props = keys(other),
idx = -1, length = props.length;
while (++idx < length) {
destination[props[idx]] = other[props[idx]];
}
return destination;
}
/**
* Create a new object with the own properties of a
* merged with the own properties of object b.
* This function will *not* mutate passed-in objects.
*
* @func
* @memberOf R
* @category Object
* @sig {k: v} -> {k: v} -> {k: v}
* @param {Object} a source object
* @param {Object} b object with higher precedence in output
* @returns {Object} Returns the destination object.
* @example
*
* R.mixin({ 'name': 'fred', 'age': 10 }, { 'age': 40 });
* //=> { 'name': 'fred', 'age': 40 }
*/
R.mixin = curry2(function _mixin(a, b) {
return extend(extend({}, a), b);
});
/**
* Creates a shallow copy of an object's own properties.
*
* @func
* @memberOf R
* @category Object
* @sig {*} -> {*}
* @param {Object} obj The object to clone
* @returns {Object} A new object
* @example
*
* R.cloneObj({a: 1, b: 2, c: [1, 2, 3]}); // {a: 1, b: 2, c: [1, 2, 3]}
*/
R.cloneObj = function(obj) {
return extend({}, obj);
};
/**
* Reports whether two functions have the same value for the specified property. Useful as a curried predicate.
*
* @func
* @memberOf R
* @category Object
* @sig k -> {k: v} -> {k: v} -> Boolean
* @param {String} prop The name of the property to compare
* @param {Object} obj1
* @param {Object} obj2
* @return {Boolean}
*
* @example
*
* 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.eqProps = curry3(function eqProps(prop, obj1, obj2) {
return obj1[prop] === obj2[prop];
});
/**
* internal helper for `where`
*
* @private
* @see R.where
*/
function satisfiesSpec(spec, parsedSpec, testObj) {
if (spec === testObj) { return true; }
if (testObj == null) { return false; }
parsedSpec.fn = parsedSpec.fn || [];
parsedSpec.obj = parsedSpec.obj || [];
var key, val, idx = -1, fnLen = parsedSpec.fn.length, j = -1, objLen = parsedSpec.obj.length;
while (++idx < fnLen) {
key = parsedSpec.fn[idx];
val = spec[key];
// if (!hasOwnProperty.call(testObj, key)) {
// return false;
// }
if (!(key in testObj)) {
return false;
}
if (!val(testObj[key], testObj)) {
return false;
}
}
while (++j < objLen) {
key = parsedSpec.obj[j];
if (spec[key] !== testObj[key]) {
return false;
}
}
return true;
}
/**
* Takes a spec object and a test object and returns true if the test satisfies the spec.
* Any property on the spec that is not a function is interpreted as an equality
* relation.
*
* If the spec has a property mapped to a function, then `where` evaluates the function, passing in
* the test object's value for the property in question, as well as the whole test object.
*
* `where` is well suited to declaratively expressing constraints for other functions, e.g.,
* `filter`, `find`, `pickWith`, etc.
*
* @func
* @memberOf R
* @category Object
* @sig {k: v} -> {k: v} -> Boolean
* @param {Object} spec
* @param {Object} testObj
* @return {Boolean}
* @example
*
* var spec = {x: 2};
* R.where(spec, {w: 10, x: 2, y: 300}); //=> true
* R.where(spec, {x: 1, y: 'moo', z: true}); //=> false
*
* var spec2 = {x: function(val, obj) { return val + obj.y > 10; }};
* R.where(spec2, {x: 2, y: 7}); //=> false
* R.where(spec2, {x: 3, y: 8}); //=> true
*
* var xs = [{x: 2, y: 1}, {x: 10, y: 2}, {x: 8, y: 3}, {x: 10, y: 4}];
* R.filter(R.where({x: 10}), xs); // ==> [{x: 10, y: 2}, {x: 10, y: 4}]
*/
R.where = function where(spec, testObj) {
var parsedSpec = R.groupBy(function(key) {
return typeof spec[key] === 'function' ? 'fn' : 'obj';
}, keys(spec));
switch (arguments.length) {
case 0: throw noArgsException();
case 1:
return function(testObj) {
return satisfiesSpec(spec, parsedSpec, testObj);
};
}
return satisfiesSpec(spec, parsedSpec, testObj);
};
// Miscellaneous Functions
// -----------------------
//
// A few functions in need of a good home.
// --------
/**
* Expose the functions from ramda as properties of another object.
* If the provided object is the global object then the ramda
* functions become global functions.
* Warning: This function *will* mutate the object provided.
*
* @func
* @memberOf R
* @category Object
* @sig -> {*} -> {*}
* @param {Object} obj The object to attach ramda functions
* @return {Object} a reference to the mutated object
* @example
*
* var x = {}
* R.installTo(x); // x now contains ramda functions
* R.installTo(this); // add ramda functions to `this` object
*/
R.installTo = function(obj) {
return extend(obj, R);
};
/**
* See if an object (`val`) is an instance of the supplied constructor.
* This function will check up the inheritance chain, if any.
*
* @func
* @memberOf R
* @category type
* @sig (* -> {*}) -> a -> Boolean
* @param {Object} ctor A constructor
* @param {*} val The value to test
* @return {Boolean}
* @example
*
* R.is(Object, {}); //=> true
* R.is(Number, 1); //=> true
* R.is(Object, 1); //=> false
* R.is(String, 's'); //=> true
* R.is(String, new String('')); //=> true
* R.is(Object, new String('')); //=> true
* R.is(Object, 's'); //=> false
* R.is(Number, {}); //=> false
*/
R.is = curry2(function is(Ctor, val) {
return val != null && val.constructor === Ctor || val instanceof Ctor;
});
/**
* A function that always returns `0`. Any passed in parameters are ignored.
*
* @func
* @memberOf R
* @category function
* @sig * -> 0
* @see R.always
* @return {Number} 0. Always zero.
* @example
*
* R.alwaysZero(); //=> 0
*/
R.alwaysZero = always(0);
/**
* A function that always returns `false`. Any passed in parameters are ignored.
*
* @func
* @memberOf R
* @category function
* @sig * -> false
* @see R.always
* @return {Boolean} false
* @example
*
* R.alwaysFalse(); //=> false
*/
R.alwaysFalse = always(false);
/**
* A function that always returns `true`. Any passed in parameters are ignored.
*
* @func
* @memberOf R
* @category function
* @sig * -> true
* @see R.always
* @return {Boolean} true
* @example
*
* R.alwaysTrue(); //=> true
*/
R.alwaysTrue = always(true);
// Logic Functions
// ---------------
//
// These functions are very simple wrappers around the built-in logical operators, useful in building up
// more complex functional forms.
// --------
/**
*
* A function wrapping calls to the two functions in an `&&` operation, returning `true` or `false`. Note that
* this is short-circuited, meaning that the second function will not be invoked if the first returns a false-y
* value.
*
* @func
* @memberOf R
* @category logic
* @sig (*... -> Boolean) -> (*... -> Boolean) -> (*... -> Boolean)
* @param {Function} f a predicate
* @param {Function} g another predicate
* @return {Function} a function that applies its arguments to `f` and `g` and ANDs their outputs together.
* @example
*
* var gt10 = function(x) { return x > 10; };
* var even = function(x) { return x % 2 === 0 };
* var f = R.and(gt10, even);
* f(100); //=> true
* f(101); //=> false
*/
R.and = curry2(function and(f, g) {
return function _and() {
return f.apply(this, arguments) && g.apply(this, arguments);
};
});
/**
* A function wrapping calls to the two functions in an `||` operation, returning `true` or `false`. Note that
* this is short-circuited, meaning that the second function will not be invoked if the first returns a truth-y
* value.
*
* @func
* @memberOf R
* @category logic
* @sig (*... -> Boolean) -> (*... -> Boolean) -> (*... -> Boolean)
* @param {Function} f a predicate
* @param {Function} g another predicate
* @return {Function} a function that applies its arguments to `f` and `g` and ORs their outputs together.
* @example
*
* var gt10 = function(x) { return x > 10; };
* var even = function(x) { return x % 2 === 0 };
* var f = R.or(gt10, even);
* f(101); //=> true
* f(8); //=> true
*/
R.or = curry2(function or(f, g) {
return function _or() {
return f.apply(this, arguments) || g.apply(this, arguments);
};
});
/**
* A function wrapping a call to the given function in a `!` operation. It will return `true` when the
* underlying function would return a false-y value, and `false` when it would return a truth-y one.
*
* @func
* @memberOf R
* @category logic
* @sig (*... -> Boolean) -> (*... -> Boolean)
* @param {Function} f a predicate
* @return {Function} a function that applies its arguments to `f` and logically inverts its output.
* @example
*
* var gt10 = function(x) { return x > 10; };
* var f = R.not(gt10);
* f(11); //=> false
* f(9); //=> true
*/
var not = R.not = function _not(f) {
return function() {return !f.apply(this, arguments);};
};
/**
* Create a predicate wrapper which will call a pick function (all/any) for each predicate
*
* @private
* @see R.every
* @see R.some
*/
// TODO: document, even for internals...
var predicateWrap = function _predicateWrap(predPicker) {
return function(preds /* , args */) {
var predIterator = function() {
var args = arguments;
return predPicker(function(predicate) {
return predicate.apply(null, args);
}, preds);
};
return arguments.length > 1 ?
// Call function immediately if given arguments
predIterator.apply(null, _slice(arguments, 1)) :
// Return a function which will call the predicates with the provided arguments
arity(max(pluck('length', preds)), predIterator);
};
};
/**
* Given a list of predicates, returns a new predicate that will be true exactly when all of them are.
*
* @func
* @memberOf R
* @category logic
* @sig [(*... -> Boolean)] -> (*... -> Boolean)
* @param {Array} list An array of predicate functions
* @param {*} optional Any arguments to pass into the predicates
* @return {Function} a function that applies its arguments to each of
* the predicates, returning `true` if all are satisfied.
* @example
*
* var gt10 = function(x) { return x > 10; };
* var even = function(x) { return x % 2 === 0};
* var f = R.allPredicates([gt10, even]);
* f(11); //=> false
* f(12); //=> true
*/
R.allPredicates = predicateWrap(every);
/**
* Given a list of predicates returns a new predicate that will be true exactly when any one of them is.
*
* @func
* @memberOf R
* @category logic
* @sig [(*... -> Boolean)] -> (*... -> Boolean)
* @param {Array} list An array of predicate functions
* @param {*} optional Any arguments to pass into the predicates
* @return {Function} a function that applies its arguments to each of the predicates, returning
* `true` if all are satisfied..
* @example
*
* var gt10 = function(x) { return x > 10; };
* var even = function(x) { return x % 2 === 0};
* var f = R.anyPredicates([gt10, even]);
* f(11); //=> true
* f(8); //=> true
* f(9); //=> false
*/
R.anyPredicates = predicateWrap(some);
/**
* Creates a function that will process either the `onTrue` or the `onFalse` function depending
* upon the result of the `condition` predicate.
*
* @func
* @memberOf R
* @category logic
* @sig (*... -> Boolean) -> (*... -> *) -> (*... -> *) -> (*... -> *)
* @param {Function} condition A condition function
* @param {Function} onTrue A predicate to invoke when the condition evaluates to a truthy value
* @param {Function} onFalse A predicate to invoke when the condition evaluates to a falsy value
* @returns {Function} a function that validates the arguments before executing "truthy"
* predicate or the the "falsey" predicate.
* @example
*
* // Flatten all arrays in the list and return whatever is not an array
* var flattenArrays = R.map(R.cond(Array.isArray, R.flatten, R.identity));
*
* flattenArrays([[0], [[10], [8]], 1234, {}]); //=> [[0], [10, 8], 1234, {}]
* flattenArrays([[[10], 123], [8, [10]], "hello"]); //=> [[10, 123], [8, 10], "hello"]
*/
R.cond = curry3(function(condition, onTrue, onFalse) {
return function _cond() {
return condition.apply(this, arguments) ? onTrue.apply(this, arguments) : onFalse.apply(this, arguments);
};
});
// Arithmetic Functions
// --------------------
//
// These functions wrap up the certain core arithmetic operators
// --------
/**
* Adds two numbers (or strings). Equivalent to `a + b` but curried.
*
* @func
* @memberOf R
* @category math
* @sig Number -> Number -> Number
* @sig String -> String -> String
* @param {number|string} a The first value.
* @param {number|string} b The second value.
* @return {number|string} The result of `a + b`.
* @example
*
* var increment = R.add(1);
* increment(10); //=> 11
* R.add(2, 3); //=> 5
* R.add(7)(10); //=> 17
*/
var add = R.add = curry2(function _add(a, b) { return a + b; });
/**
* Multiplies two numbers. Equivalent to `a * b` but curried.
*
* @func
* @memberOf R
* @category math
* @sig Number -> Number -> Number
* @param {number} a The first value.
* @param {number} b The second value.
* @return {number} The result of `a * b`.
* @example
*
* var double = R.multiply(2);
* var triple = R.multiply(3);
* double(3); //=> 6
* triple(4); //=> 12
* R.multiply(2, 5); //=> 10
*/
var multiply = R.multiply = curry2(function _multiply(a, b) { return a * b; });
/**
* Subtracts two numbers. Equivalent to `a - b` but curried.
*
* @func
* @memberOf R
* @category math
* @sig Number -> Number -> Number
* @param {number} a The first value.
* @param {number} b The second value.
* @return {number} The result of `a - b`.
* @note Operator: Since this is a non-commutative infix operator converted to prefix, it can
* be curried right by explicitly passing `undefined` for its first argument.
* @example
*
* R.subtract(10, 8); //=> 2
*
* var minus5 = R.subtract(__, 5); // '__' stands for any `undefined` value
* minus5(17); //=> 12
*
* // note: In this example, `_` is just an `undefined` value. You could use `void 0` instead
* var complementaryAngle = R.subtract(90);
* complementaryAngle(30); //=> 60
* complementaryAngle(72); //=> 18
*/
R.subtract = op(function _subtract(a, b) { return a - b; });
/**
* Divides two numbers. Equivalent to `a / b`.
*
* @func
* @memberOf R
* @category math
* @sig Number -> Number -> Number
* @param {number} a The first value.
* @param {number} b The second value.
* @return {number} The result of `a / b`.
* @note Operator: Since this is a non-commutative infix operator converted to prefix, it can
* be curried right by explicitly passing `undefined` for its first argument.
* @example
*
* R.divide(71, 100); //=> 0.71
*
* // note: In this example, `__` is just an `undefined` value. You could use `void 0` instead
* var half = R.divide(__, 2);
* half(42); //=> 21
*
* var reciprocal = R.divide(1);
* reciprocal(4); //=> 0.25
*/
R.divide = op(function _divide(a, b) { return a / b; });
/**
* Divides the second parameter by the first and returns the remainder.
* Note that this functions preserves the JavaScript-style behavior for
* modulo. For mathematical modulo see `mathMod`
*
* @func
* @memberOf R
* @category math
* @sig Number -> Number -> Number
* @param {number} a The value to the divide.
* @param {number} b The pseudo-modulus
* @return {number} The result of `b % a`.
* @note Operator: Since this is a non-commutative infix operator converted to prefix, it can
* be curried right by explicitly passing `undefined` for its first argument.
* @see R.mathMod
* @example
*
* R.modulo(17, 3); //=> 2
* // JS behavior:
* R.modulo(-17, 3); //=> -2
* R.modulo(17, -3); //=> 2
*
* var isOdd = R.modulo(__, 2);
* isOdd(42); //=> 0
* isOdd(21); //=> 1
*/
R.modulo = op(function _modulo(a, b) { return a % b; });
/**
* Determine if the passed argument is an integer.
*
* @private
* @param {*} n
* @category type
* @return {Boolean}
*/
// TODO: document, even for internals...
var isInteger = Number.isInteger || function isInteger(n) {
return (n << 0) === n;
};
/**
* mathMod behaves like the modulo operator should mathematically, unlike the `%`
* operator (and by extension, R.modulo). So while "-17 % 5" is -2,
* mathMod(-17, 5) is 3. mathMod requires Integer arguments, and returns NaN
* when the modulus is zero or negative.
*
* @func
* @memberOf R
* @category math
* @sig Number -> Number -> Number
* @param {number} m The dividend.
* @param {number} p the modulus.
* @return {number} The result of `b mod a`.
* @see R.moduloBy
* @note Operator: Since this is a non-commutative infix operator converted to prefix, it can
* be curried right by explicitly passing `undefined` for its first argument.
* @example
*
* R.mathMod(-17, 5); //=> 3
* R.mathMod(17, 5); //=> 2
* R.mathMod(17, -5); //=> NaN
* R.mathMod(17, 0); //=> NaN
* R.mathMod(17.2, 5); //=> NaN
* R.mathMod(17, 5.3); //=> NaN
*
* var clock = R.mathMod(__, 12);
* clock(15); //=> 3
* clock(24); //=> 0
*
* // note: In this example, `_` is just an `undefined` value. You could use `void 0` instead
* var seventeenMod = R.mathMod(17);
* seventeenMod(3); //=> 2
* seventeenMod(4); //=> 1
* seventeenMod(10); //=> 7
*/
R.mathMod = op(function _mathMod(m, p) {
if (!isInteger(m)) { return NaN; }
if (!isInteger(p) || p < 1) { return NaN; }
return ((m % p) + p) % p;
});
/**
* Adds together all the elements of a list.
*
* @func
* @memberOf R
* @category math
* @sig [Number] -> Number
* @param {Array} list An array of numbers
* @return {number} The sum of all the numbers in the list.
* @see reduce
* @example
*
* R.sum([2,4,6,8,100,1]); //=> 121
*/
R.sum = foldl(add, 0);
/**
* Multiplies together all the elements of a list.
*
* @func
* @memberOf R
* @category math
* @sig [Number] -> Number
* @param {Array} list An array of numbers
* @return {number} The product of all the numbers in the list.
* @see reduce
* @example
*
* R.product([2,4,6,8,100,1]); //=> 38400
*/
R.product = foldl(multiply, 1);
/**
* Returns true if the first parameter is less than the second.
*
* @func
* @memberOf R
* @category math
* @sig Number -> Number -> Boolean
* @param {Number} a
* @param {Number} b
* @return {Boolean} a < b
* @note Operator: Since this is a non-commutative infix operator converted to prefix, it can
* be curried right by explicitly passing `undefined` for its first argument.
* @example
*
* R.lt(2, 6); //=> true
* R.lt(2, 0); //=> false
* R.lt(2, 2); //=> false
* R.lt(5)(10); //=> true
* R.lt(__, 5)(10); //=> false // right-sectioned currying
*/
function lt(a, b) { return a < b; }
R.lt = op(lt);
/**
* Returns true if the first parameter is less than or equal to the second.
*
* @func
* @memberOf R
* @category math
* @sig Number -> Number -> Boolean
* @param {Number} a
* @param {Number} b
* @return {Boolean} a <= b
* @note Operator: Since this is a non-commutative infix operator converted to prefix, it can
* be curried right by explicitly passing `undefined` for its first argument.
* @example
*
* R.lte(2, 6); //=> true
* R.lte(2, 0); //=> false
* R.lte(2, 2); //=> true
* R.lte(__, 2)(1); //=> true
* R.lte(2)(10); //=> true
* R.lte(__)(5, 4) // => true
*/
R.lte = op(function _lte(a, b) { return a <= b; });
/**
* Returns true if the first parameter is greater than the second.
*
* @func
* @memberOf R
* @category math
* @sig Number -> Number -> Boolean
* @param {Number} a
* @param {Number} b
* @return {Boolean} a > b
* @note Operator: Since this is a non-commutative infix operator converted to prefix, it can
* be curried right by explicitly passing `undefined` for its first argument.
* @example
*
* R.gt(2, 6); //=> false
* R.gt(2, 0); //=> true
* R.gt(2, 2); //=> false
* R.gt(__, 2)(10); //=> true
* R.gt(2)(10); //=> false
* R.lte(__)(4, 5) // => true
*/
function gt(a, b) { return a > b; }
R.gt = op(gt);
/**
* Returns true if the first parameter is greater than or equal to the second.
*
* @func
* @memberOf R
* @category math
* @sig Number -> Number -> Boolean
* @param {Number} a
* @param {Number} b
* @return {Boolean} a >= b
* @note Operator: this is right-curried by default, but can be called via sections
* @example
*
* R.gte(2, 6); //=> false
* R.gte(2, 0); //=> true
* R.gte(2, 2); //=> true
* R.gte(__, 6)(2); //=> false
* R.gte(2)(0); //=> true
* R.gte(__)(1, 2); //=> true
*/
R.gte = op(function _gte(a, b) { return a >= b; });
/**
* Create a function which takes a a list
* and determines the winning value by a compatator. Used internally
* by `R.max` and `R.min`
*
* @private
* @param {Function} compatator a function to compare two items
* @param {*} intialVal, default value if nothing else wins
* @category math
* @return {Function}
*/
function createMaxMin(comparator, initialVal) {
return function(list) {
if (arguments.length === 0) {
throw noArgsException();
}
var idx = -1, winner = initialVal, computed;
while (++idx < list.length) {
computed = +list[idx];
if (comparator(computed, winner)) {
winner = computed;
}
}
return winner;
};
}
/**
* Create a function which takes a comparator function and a list
* and determines the winning value by a compatator. Used internally
* by `R.maxWith` and `R.minWith`
*
* @private
* @param {Function} compatator a function to compare two items
* @category math
* @return {Function}
*/
function createMaxMinWith(comparator) {
return function(valueComputer, list) {
if (!(list && list.length > 0)) {
return;
}
var idx = 0,
winner = list[idx],
computedWinner = valueComputer(winner),
computedCurrent;
while (++idx < list.length) {
computedCurrent = valueComputer(list[idx]);
if (comparator(computedCurrent, computedWinner)) {
computedWinner = computedCurrent;
winner = list[idx];
}
}
return winner;
};
}
/**
* Determines the largest of a list of numbers (or elements that can be cast to numbers)
*
* @func
* @memberOf R
* @category math
* @sig [Number] -> Number
* @see R.maxWith
* @param {Array} list A list of numbers
* @return {Number} The greatest number in the list
* @example
*
* R.max([7, 3, 9, 2, 4, 9, 3]); //=> 9
*/
var max = R.max = createMaxMin(gt, -Infinity);
/**
* Determines the largest of a list of items as determined by pairwise comparisons from the supplied comparator
*
* @func
* @memberOf R
* @category math
* @sig (a -> Number) -> [a] -> a
* @param {Function} keyFn A comparator function for elements in the list
* @param {Array} list A list of comparable elements
* @return {*} The greatest element in the list. `undefined` if the list is empty.
* @see R.max
* @example
*
* function cmp(obj) { return obj.x; }
* var a = {x: 1}, b = {x: 2}, c = {x: 3};
* R.maxWith(cmp, [a, b, c]); //=> {x: 3}
*/
R.maxWith = curry2(createMaxMinWith(gt));
/**
* Determines the smallest of a list of numbers (or elements that can be cast to numbers)
*
* @func
* @memberOf R
* @category math
* @sig [Number] -> Number
* @param {Array} list A list of numbers
* @return {Number} The greatest number in the list
* @see R.minWith
* @example
*
* R.min([7, 3, 9, 2, 4, 9, 3]); //=> 2
*/
R.min = createMaxMin(lt, Infinity);
/**
* Determines the smallest of a list of items as determined by pairwise comparisons from the supplied comparator
*
* @func
* @memberOf R
* @category math
* @sig (a -> Number) -> [a] -> a
* @param {Function} keyFn A comparator function for elements in the list
* @param {Array} list A list of comparable elements
* @see R.min
* @return {*} The greatest element in the list. `undefined` if the list is empty.
* @example
*
* function cmp(obj) { return obj.x; }
* var a = {x: 1}, b = {x: 2}, c = {x: 3};
* R.minWith(cmp, [a, b, c]); //=> {x: 1}
*/
R.minWith = curry2(createMaxMinWith(lt));
// String Functions
// ----------------
//
// Much of the String.prototype API exposed as simple functions.
// --------
/**
* returns a subset of a string between one index and another.
*
* @func
* @memberOf R
* @category string
* @sig Number -> Number -> String -> String
* @param {Number} indexA An integer between 0 and the length of the string.
* @param {Number} indexB An integer between 0 and the length of the string.
* @param {String} str The string to extract from
* @return {String} the extracted substring
* @see R.invoker
* @example
*
* R.substring(2, 5, 'abcdefghijklm'); //=> 'cde'
*/
var substring = R.substring = invoker(String.prototype.substring);
/**
* The trailing substring of a String starting with the nth character:
*
* @func
* @memberOf R
* @category string
* @sig Number -> String -> String
* @param {Number} indexA An integer between 0 and the length of the string.
* @param {String} str The string to extract from
* @return {String} the extracted substring
* @see R.invoker
* @example
*
* R.substringFrom(8, 'abcdefghijklm'); //=> 'ijklm'
*/
R.substringFrom = flip(substring)(void 0);
/**
* The leading substring of a String ending before the nth character:
*
* @func
* @memberOf R
* @category string
* @sig Number -> String -> String
* @param {Number} indexA An integer between 0 and the length of the string.
* @param {String} str The string to extract from
* @return {String} The extracted substring
* @see R.invoker
* @example
*
* R.substringTo(8, 'abcdefghijklm'); //=> 'abcdefgh'
*/
R.substringTo = substring(0);
/**
* The character at the nth position in a String:
*
* @func
* @memberOf R
* @category string
* @sig Number -> String -> String
* @param {Number} index An integer between 0 and the length of the string.
* @param {String} str The string to extract a char from
* @return {String} the character at `index` of `str`
* @see R.invoker
* @example
*
* R.charAt(8, 'abcdefghijklm'); //=> 'i'
*/
R.charAt = invoker(String.prototype.charAt);
/**
* The ascii code of the character at the nth position in a String:
*
* @func
* @memberOf R
* @category string
* @sig Number -> String -> Number
* @param {Number} index An integer between 0 and the length of the string.
* @param {String} str The string to extract a charCode from
* @return {Number} the code of the character at `index` of `str`
* @see R.invoker
* @example
*
* R.charCodeAt(8, 'abcdefghijklm'); //=> 105
* // (... 'a' ~ 97, 'b' ~ 98, ... 'i' ~ 105)
*/
R.charCodeAt = invoker(String.prototype.charCodeAt);
/**
* Tests a regular expression against a String
*
* @func
* @memberOf R
* @category string
* @sig RegExp -> String -> [String] | null
* @param {RegExp} rx A regular expression.
* @param {String} str The string to match against
* @return {Array} The list of matches, or null if no matches found
* @see R.invoker
* @example
*
* R.match(/([a-z]a)/g, 'bananas'); //=> ['ba', 'na', 'na']
*/
R.match = invoker(String.prototype.match);
/**
* Replace a substring or regex match in a string with a replacement.
*
* @func
* @memberOf R
* @category string
* @sig RegExp|String -> String -> String -> String
* @param {RegExp|String} pattern A regular expression or a substring to match.
* @param {String} replacement The string to replace the matches with.
* @param {String} str The String to do the search and replacement in.
* @return {String} A string with all the matches replaced.
* @example
*
* R.replace(/\d+/g, 'number', '1 2 three'); //=> 'number number three'
*
* var replaceSemicolon = R.replace(';');
* var removeSemicolon = replaceSemicolon('');
* removeSemicolon('return 42;'); //=> 'return 42'
*/
R.replace = curry3(function _replace(regex, replacement, str) {
return str.replace(regex, replacement);
});
/**
* Finds the first index of a substring in a string, returning -1 if it's not present
*
* @func
* @memberOf R
* @category string
* @sig String -> String -> Number
* @param {String} c A string to find.
* @param {String} str The string to search in
* @return {Number} The first index of `c` or -1 if not found
* @see R.invoker
* @example
*
* R.strIndexOf('c', 'abcdefg'); //=> 2
*/
R.strIndexOf = curry2(function _strIndexOf(c, str) {
return str.indexOf(c);
});
/**
*
* Finds the last index of a substring in a string, returning -1 if it's not present
*
* @func
* @memberOf R
* @category string
* @sig String -> String -> Number
* @param {String} c A string to find.
* @param {String} str The string to search in
* @return {Number} The last index of `c` or -1 if not found
* @see R.invoker
* @example
*
* R.strLastIndexOf('a', 'banana split'); //=> 5
*/
R.strLastIndexOf = curry2(function(c, str) {
return str.lastIndexOf(c);
});
/**
* The upper case version of a string.
*
* @func
* @memberOf R
* @category string
* @sig String -> String
* @param {string} str The string to upper case.
* @return {string} The upper case version of `str`.
* @example
*
* R.toUpperCase('abc'); //=> 'ABC'
*/
R.toUpperCase = invoker(String.prototype.toUpperCase);
/**
* The lower case version of a string.
*
* @func
* @memberOf R
* @category string
* @sig String -> String
* @param {string} str The string to lower case.
* @return {string} The lower case version of `str`.
* @example
*
* R.toLowerCase('XYZ'); //=> 'xyz'
*/
R.toLowerCase = invoker(String.prototype.toLowerCase);
/**
* Removes whitespace from both ends of the string.
*
* @func
* @memberOf R
* @category string
* @sig String -> String
* @param {String} str The string to trim.
* @returns {String} Trimmed version of `str`.
* @example
*
* R.trim(' xyz '); //=> 'xyz'
* R.map(R.trim, R.split(',', 'x, y, z')); //=> ['x', 'y', 'z']
*/
R.trim = (function() {
var ws = '\x09\x0A\x0B\x0C\x0D\x20\xA0\u1680\u180E\u2000\u2001\u2002\u2003' +
'\u2004\u2005\u2006\u2007\u2008\u2009\u200A\u202F\u205F\u3000\u2028' +
'\u2029\uFEFF';
var zeroWidth = '\u200b';
var hasProtoTrim = (typeof String.prototype.trim === 'function');
if (!hasProtoTrim || (ws.trim() || !zeroWidth.trim())) {
return function _trim(str) {
var beginRx = new RegExp('^[' + ws + '][' + ws + ']*');
var endRx = new RegExp('[' + ws + '][' + ws + ']*$');
return str.replace(beginRx, '').replace(endRx, '');
};
}
return function trim(str) { return str.trim(str); };
}());
/**
* Splits a string into an array of strings based on the given
* separator.
*
* @func
* @memberOf R
* @category string
* @sig String -> String -> [String]
* @param {string} sep The separator string.
* @param {string} str The string to separate into an array.
* @return {Array} The array of strings from `str` separated by `str`.
* @example
*
* var pathComponents = R.split('/');
* R.tail(pathComponents('/usr/local/bin/node')); //=> ['usr', 'local', 'bin', 'node']
*
* R.split('.', 'a.b.c.xyz.d'); //=> ['a', 'b', 'c', 'xyz', 'd']
*/
R.split = invokerN(1, String.prototype.split);
/**
* internal path function
* Takes an array, paths, indicating the deep set of keys
* to find.
*
* @private
* @memberOf R
* @category object
* @param {Array} paths An array of strings to map to object properties
* @param {Object} obj The object to find the path in
* @return {Array} The value at the end of the path or `undefined`.
* @example
*
* path(['a', 'b'], {a: {b: 2}}); //=> 2
*/
function path(paths, obj) {
var idx = -1, length = paths.length, val;
if (obj == null) { return; }
val = obj;
while (val != null && ++idx < length) {
val = val[paths[idx]];
}
return val;
}
/**
* Retrieve a nested path on an object separated by the specified
* separator value.
*
* @func
* @memberOf R
* @category object
* @sig String -> String -> {*} -> *
* @param {string} sep The separator to use in `path`.
* @param {string} path The path to use.
* @return {*} The data at `path`.
* @example
*
* R.pathOn('/', 'a/b/c', {a: {b: {c: 3}}}); //=> 3
*/
R.pathOn = curry3(function pathOn(sep, str, obj) {
return path(str.split(sep), obj);
});
/**
* Retrieve a nested path on an object separated by periods
*
* @func
* @memberOf R
* @category object
* @sig String -> {*} -> *
* @param {string} path The dot path to use.
* @return {*} The data at `path`.
* @example
*
* R.path('a.b', {a: {b: 2}}); //=> 2
*/
R.path = R.pathOn('.');
/**
* Determines whether a nested path on an object, seperated by periods,
* has a specific value according to strict equality ('==='). Most
* likely used to filter a list:
*
* @func
* @memberOf R
* @category relation
* @sig String -> v -> {k: v} -> Boolean
* @param {string} path The path of the nested property to use
* @param {*} val The value to compare the nested property with
* @param {Object} obj The object to check the nested property in
* @return {boolean} `true` if the value equals the nested object property,
* `false` otherwise.
* @example
*
* 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 ]
*/
R.pathEq = curry3(function(path, val, obj) {
return R.eq(val, R.path(path, obj));
});
// Data Analysis and Grouping Functions
// ------------------------------------
//
// Functions performing SQL-like actions on lists of objects. These do
// not have any SQL-like optimizations performed on them, however.
// --------
/**
* Reasonable analog to SQL `select` statement.
*
* @func
* @memberOf R
* @category object
* @category relation
* @sig [k] -> [{k: v}] -> [{k: v}]
* @param {Array} props The property names to project
* @param {Array} objs The objects to query
* @return {Array} An array of objects with just the `props` properties.
* @example
*
* 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}]
*/
R.project = useWith(map, R.pickAll, identity); // passing `identity` gives correct arity
/**
* Determines whether the given property of an object has a specific
* value according to strict equality (`===`). Most likely used to
* filter a list:
*
* @func
* @memberOf R
* @category relation
* @sig k -> v -> {k: v} -> Boolean
* @param {string|number} name The property name (or index) to use.
* @param {*} val The value to compare the property with.
* @return {boolean} `true` if the properties are equal, `false` otherwise.
* @example
*
* 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]
*/
R.propEq = curry3(function propEq(name, val, obj) {
return obj[name] === val;
});
/**
* Combines two lists into a set (i.e. no duplicates) composed of the
* elements of each list.
*
* @func
* @memberOf R
* @category relation
* @sig [a] -> [a] -> [a]
* @param {Array} as The first list.
* @param {Array} bs The second list.
* @return {Array} The first and second lists concatenated, with
* duplicates removed.
* @example
*
* R.union([1, 2, 3], [2, 3, 4]); //=> [1, 2, 3, 4]
*/
R.union = compose(uniq, R.concat);
/**
* Combines two lists into a set (i.e. no duplicates) composed of the elements of each list. Duplication is
* determined according to the value returned by applying the supplied predicate to two list elements.
*
* @func
* @memberOf R
* @category relation
* @sig (a,a -> Boolean) -> [a] -> [a] -> [a]
* @param {Function} pred A predicate used to test whether two items are equal.
* @param {Array} list1 The first list.
* @param {Array} list2 The second list.
* @return {Array} The first and second lists concatenated, with
* duplicates removed.
* @see R.union
* @example
*
* function cmp(x, y) { return x.a === y.a; }
* var l1 = [{a: 1}, {a: 2}];
* var l2 = [{a: 1}, {a: 4}];
* R.unionWith(cmp, l1, l2); //=> [{a: 1}, {a: 2}, {a: 4}]
*/
R.unionWith = curry3(function _unionWith(pred, list1, list2) {
return uniqWith(pred, concat(list1, list2));
});
/**
* Finds the set (i.e. no duplicates) of all elements in the first list not contained in the second list.
*
* @func
* @memberOf R
* @category relation
* @sig [a] -> [a] -> [a]
* @param {Array} list1 The first list.
* @param {Array} list2 The second list.
* @return {Array} The elements in `list1` that are not in `list2`
* @see R.differenceWith
* @example
*
* 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 = curry2(function _difference(first, second) {
var out = [];
var idx = -1;
var firstLen = first.length;
while (++idx < firstLen) {
if (indexOf(second, first[idx]) === -1 && indexOf(out, first[idx]) === -1) {
out.push(first[idx]);
}
}
return out;
});
/**
* Finds the set (i.e. no duplicates) of all elements in the first list not contained in the second list.
* Duplication is determined according to the value returned by applying the supplied predicate to two list
* elements.
*
* @func
* @memberOf R
* @category relation
* @sig (a,a -> Boolean) -> [a] -> [a] -> [a]
* @param {Function} pred A predicate used to test whether two items are equal.
* @param {Array} list1 The first list.
* @param {Array} list2 The second list.
* @see R.difference
* @return {Array} The elements in `list1` that are not in `list2`
* @example
*
* function cmp(x, y) { return 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}]
*
*/
R.differenceWith = curry3(function differenceWith(pred, first, second) {
var out = [];
var idx = -1;
var firstLen = first.length;
var containsPred = R.containsWith(pred);
while (++idx < firstLen) {
if (!containsPred(first[idx], second) && !containsPred(first[idx], out)) {
out.push(first[idx]);
}
}
return out;
});
/**
* Combines two lists into a set (i.e. no duplicates) composed of those elements common to both lists.
*
* @func
* @memberOf R
* @category relation
* @sig [a] -> [a] -> [a]
* @param {Array} list1 The first list.
* @param {Array} list2 The second list.
* @see R.intersectionWith
* @return {Array} The list of elements found in both `list1` and `list2`
* @example
*
* R.intersection([1,2,3,4], [7,6,5,4,3]); //=> [4, 3]
*/
R.intersection = curry2(function intersection(list1, list2) {
return uniq(filter(flip(contains)(list1), list2));
});
/**
* Combines two lists into a set (i.e. no duplicates) composed of those
* elements common to both lists. Duplication is determined according
* to the value returned by applying the supplied predicate to two list
* elements.
*
* @func
* @memberOf R
* @category relation
* @sig (a,a -> Boolean) -> [a] -> [a] -> [a]
* @param {Function} pred A predicate function that determines whether
* the two supplied elements are equal.
* @param {Array} list1 One list of items to compare
* @param {Array} list2 A second list of items to compare
* @see R.intersection
* @return {Array} A new list containing those elements common to both lists.
* @example
*
* 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'}
* ];
*
* var sameId = function(o1, o2) {return o1.id === o2.id;};
*
* R.intersectionWith(sameId, buffaloSpringfield, csny);
* //=> [{id: 456, name: 'Stephen Stills'}, {id: 177, name: 'Neil Young'}]
*/
R.intersectionWith = curry3(function intersectionWith(pred, list1, list2) {
var results = [], idx = -1;
while (++idx < list1.length) {
if (containsWith(pred, list1[idx], list2)) {
results[results.length] = list1[idx];
}
}
return uniqWith(pred, results);
});
/**
* Creates a new list whose elements each have two properties: `val` is
* the value of the corresponding item in the list supplied, and `key`
* is the result of applying the supplied function to that item.
*
* @private
* @func
* @memberOf R
* @category relation
* @param {Function} fn An arbitrary unary function returning a potential
* object key. Signature: Any -> String
* @param {Array} list The list of items to process
* @return {Array} A new list with the described structure.
* @example
*
* var people = [
* {first: 'Fred', last: 'Flintstone', age: 23},
* {first: 'Betty', last: 'Rubble', age: 21},
* {first: 'George', last: 'Jetson', age: 29}
* ];
*
* var fullName = function(p) {return p.first + ' ' + p.last;};
*
* keyValue(fullName, people); //=>
* // [
* // {
* // key: 'Fred Flintstone',
* // val: {first: 'Fred', last: 'Flintstone', age: 23}
* // }, {
* // key: 'Betty Rubble',
* // val: {first: 'Betty', last: 'Rubble', age: 21}
* // }, {
* // key: 'George Jetson',
* // val: {first: 'George', last: 'Jetson', age: 29}
* // }
* // ];
*/
function keyValue(fn, list) { // TODO: Should this be made public?
return map(function(item) {return {key: fn(item), val: item};}, list);
}
/**
* Compare two items from a list generated from the `keyValue`
* function. Used internally by sortBy.
*
* @private
* @func
* @category relation
* @param {*} a
* @param {*} b
*/
var compareKeys = comparator(function(a, b) {
return a.key < b.key;
});
/**
* Sorts the list according to a key generated by the supplied function.
*
* @func
* @memberOf R
* @category relation
* @sig (a -> String) -> [a] -> [a]
* @param {Function} fn The function mapping `list` items to keys.
* @param {Array} list The list to sort.
* @return {Array} A new list sorted by the keys generated by `fn`.
* @example
*
* var sortByFirstItem = R.sortBy(prop(0));
* var sortByNameCaseInsensitive = R.sortBy(compose(R.toLowerCase, prop('name')));
* var pairs = [[-1, 1], [-2, 2], [-3, 3]];
* sortByFirstItem(pairs); //=> [[-3, 3], [-2, 2], [-1, 1]]
* 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]
*/
R.sortBy = curry2(function sortBy(fn, list) {
return pluck('val', keyValue(fn, list).sort(compareKeys));
});
/**
* Counts the elements of a list according to how many match each value
* of a key generated by the supplied function. Returns an object
* mapping the keys produced by `fn` to the number of occurrences in
* the list. Note that all keys are coerced to strings because of how
* JavaScript objects work.
*
* @func
* @memberOf R
* @category relation
* @sig (a -> String) -> [a] -> {*}
* @param {Function} fn The function used to map values to keys.
* @param {Array} list The list to count elements from.
* @return {Object} An object mapping keys to number of occurrences in the list.
* @example
*
* var numbers = [1.0, 1.1, 1.2, 2.0, 3.0, 2.2];
* var letters = R.split('', 'abcABCaaaBBc');
* R.countBy(Math.floor)(numbers); //=> {'1': 3, '2': 2, '3': 1}
* R.countBy(R.toLowerCase)(letters); //=> {'a': 5, 'b': 4, 'c': 3}
*/
R.countBy = curry2(function countBy(fn, list) {
return foldl(function(counts, obj) {
counts[obj.key] = (counts[obj.key] || 0) + 1;
return counts;
}, {}, keyValue(fn, list));
});
/**
* @private
* @param {Function} fn The strategy for extracting function names from an object
* @return {Function} A function that takes an object and returns an array of function names
*
*/
var functionsWith = function(fn) {
return function(obj) {
return R.filter(function(key) { return typeof obj[key] === 'function'; }, fn(obj));
};
};
/**
* Returns a list of function names of object's own functions
*
* @func
* @memberOf R
* @category Object
* @sig {*} -> [String]
* @param {Object} obj The objects with functions in it
* @return {Array} returns a list of the object's own properties that map to functions
* @example
*
* R.functions(R); // returns list of ramda's own function names
*
* var F = function() { this.x = function(){}; this.y = 1; }
* F.prototype.z = function() {};
* F.prototype.a = 100;
* R.functions(new F()); //=> ["x"]
*/
R.functions = functionsWith(R.keys);
/**
* Returns a list of function names of object's own and prototype functions
*
* @func
* @memberOf R
* @category Object
* @sig {*} -> [String]
* @param {Object} obj The objects with functions in it
* @return {Array} returns a list of the object's own properties and prototype
* properties that map to functions
* @example
*
* R.functionsIn(R); // returns list of ramda's own and prototype function names
*
* var F = function() { this.x = function(){}; this.y = 1; }
* F.prototype.z = function() {};
* F.prototype.a = 100;
* R.functionsIn(new F()); //=> ["x", "z"]
*/
R.functionsIn = functionsWith(R.keysIn);
// All the functional goodness, wrapped in a nice little package, just for you!
return R;
}));