Skip to content

Commit

Permalink
Implemented addIndexRight (ramda#2140)
Browse files Browse the repository at this point in the history
  • Loading branch information
briancaine authored Feb 5, 2022
1 parent 6d2f477 commit c2cafc2
Show file tree
Hide file tree
Showing 3 changed files with 122 additions and 0 deletions.
42 changes: 42 additions & 0 deletions source/addIndexRight.js
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;
1 change: 1 addition & 0 deletions source/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ export { default as T } from './T.js';
export { default as __ } from './__.js';
export { default as add } from './add.js';
export { default as addIndex } from './addIndex.js';
export { default as addIndexRight } from './addIndexRight.js';
export { default as adjust } from './adjust.js';
export { default as all } from './all.js';
export { default as allPass } from './allPass.js';
Expand Down
79 changes: 79 additions & 0 deletions test/addIndexRight.js
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
});

});

});

0 comments on commit c2cafc2

Please sign in to comment.