forked from ramda/ramda
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Implemented addIndexRight (ramda#2140)
- Loading branch information
1 parent
6d2f477
commit c2cafc2
Showing
3 changed files
with
122 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
import _concat from './internal/_concat.js'; | ||
import _curry1 from './internal/_curry1.js'; | ||
import curryN from './curryN.js'; | ||
|
||
|
||
/** | ||
* As with `addIndex`, `addIndexRight` creates a new list iteration function | ||
* from an existing one by adding two new parameters to its callback function: | ||
* the current index, and the entire list. | ||
* | ||
* Unlike `addIndex`, `addIndexRight` iterates from the right to the left. | ||
* | ||
* @func | ||
* @memberOf R | ||
* @category Function | ||
* @category List | ||
* @sig ((a ... -> b) ... -> [a] -> *) -> (a ..., Int, [a] -> b) ... -> [a] -> *) | ||
* @param {Function} fn A list iteration function that does not pass index or list to its callback | ||
* @return {Function} An altered list iteration function that passes (item, index, list) to its callback | ||
* @example | ||
* | ||
* const revmap = (fn, ary) => R.map(fn, R.reverse(ary)); | ||
* const revmapIndexed = R.addIndexRight(revmap); | ||
* revmapIndexed((val, idx) => idx + '-' + val, ['f', 'o', 'o', 'b', 'a', 'r']); | ||
* //=> [ '5-r', '4-a', '3-b', '2-o', '1-o', '0-f' ] | ||
*/ | ||
var addIndexRight = _curry1(function addIndex(fn) { | ||
return curryN(fn.length, function() { | ||
var origFn = arguments[0]; | ||
var list = arguments[arguments.length - 1]; | ||
var idx = list.length - 1; | ||
var args = Array.prototype.slice.call(arguments, 0); | ||
args[0] = function() { | ||
var result = origFn.apply(this, _concat(arguments, [idx, list])); | ||
idx -= 1; | ||
return result; | ||
}; | ||
return fn.apply(this, args); | ||
}); | ||
}); | ||
|
||
export default addIndexRight; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,79 @@ | ||
var R = require('../source/index.js'); | ||
var eq = require('./shared/eq.js'); | ||
|
||
|
||
describe('addIndexRight', function() { | ||
describe('unary functions like `map`', function() { | ||
var times2 = function(x) {return x * 2;}; | ||
var addIndexParam = function(x, idx) {return x + idx;}; | ||
var squareEnds = function(x, idx, list) { | ||
return (idx === 0 || idx === list.length - 1) ? x * x : x; | ||
}; | ||
var revmap = function(fn, ary) { return R.map(fn, R.reverse(ary)); }; | ||
var revmapIndexed = R.addIndexRight(revmap); | ||
|
||
it('works just like a normal (reversed) map', function() { | ||
eq(revmapIndexed(times2, [1, 2, 3, 4]), [8, 6, 4, 2]); | ||
}); | ||
|
||
it('passes the index as a second parameter to the callback', function() { | ||
eq(revmapIndexed(addIndexParam, [8, 6, 7, 5, 3, 0, 9]), [15, 5, 7, 8, 9, 7, 8]); // [9 + 6, 0 + 5...] | ||
}); | ||
|
||
it('passes the entire list as a third parameter to the callback', function() { | ||
eq(revmapIndexed(squareEnds, [8, 6, 7, 5, 3, 0, 9]), [81, 0, 3, 5, 7, 6, 64]); | ||
}); | ||
|
||
it('acts as a curried function', function() { | ||
var makeSquareEnds = revmapIndexed(squareEnds); | ||
eq(makeSquareEnds([8, 6, 7, 5, 3, 0, 9]), [81, 0, 3, 5, 7, 6, 64]); | ||
}); | ||
|
||
}); | ||
|
||
describe('binary functions like `reduce`', function() { | ||
var reduceRightIndexed = R.addIndexRight(R.reduceRight); | ||
var timesIndexed = function(num, tot, idx) { return tot + (num * idx);}; | ||
var objectify = function(elem, acc, idx) { acc[elem] = idx; return acc;}; | ||
|
||
it('passes the index as a third parameter to the predicate', function() { | ||
eq(reduceRightIndexed(timesIndexed, 0, [1, 2, 3, 4, 5]), 40); | ||
eq(reduceRightIndexed(objectify, {}, ['a', 'b', 'c', 'd', 'e']), {a: 0, b: 1, c: 2, d: 3, e: 4}); | ||
}); | ||
|
||
it('passes the entire list as a fourth parameter to the predicate', function() { | ||
var list = [1, 2, 3]; | ||
reduceRightIndexed(function(acc, x, idx, ls) { | ||
eq(ls, list); | ||
return acc; | ||
}, 0, list); | ||
}); | ||
|
||
}); | ||
|
||
describe('works with functions like `all` that do not typically have index applied', function() { | ||
var allIndexed = R.addIndexRight(R.all); | ||
var superDiagonal = allIndexed(R.gt); | ||
it('passes the index as a second parameter', function() { | ||
eq(superDiagonal([8, 6, 5, 4, 9]), true); // 8 > 0, 6 > 1, 5 > 2, 4 > 3, 9 > 5 | ||
eq(superDiagonal([8, 6, 1, 3, 9]), false); // 1 !> 2, 3 !> 3 | ||
}); | ||
|
||
}); | ||
|
||
describe('works with arbitrary user-defined functions', function() { | ||
var revmapFilter = function(m, f, list) { | ||
return R.filter(R.compose(f, m), R.reverse(list)); | ||
}; | ||
var revmapFilterIndexed = R.addIndexRight(revmapFilter); | ||
it('passes the index as an additional parameter', function() { | ||
eq(revmapFilterIndexed( | ||
R.multiply, | ||
R.gt(R.__, 13), | ||
[8, 6, 7, 5, 3, 0, 9] | ||
), [9, 5, 7]); // 6 * 9 > 13, 3 * 5 > 13, 2 * 7 > 13 | ||
}); | ||
|
||
}); | ||
|
||
}); |