I'm using the JS library Underscore and in particular using the _.each
and _.sortby
library calls. I'm wondering if there's any possible way to get the index of the value within the iterator delegate
_.sortBy([1, 4, 2, 66, 444, 9], function(num){
/*It'd be great to have access to the index in here */
return Math.sin(num);
});
This question is related to
javascript
underscore.js
The iterator of _.each
is called with 3 parameters (element, index, list)
. So yes, for _.each
you cab get the index.
You can do the same in sortBy
More generally, under most circumstances, underscore functions that take a list and argument as the first two arguments, provide access to the list index as the next to last argument to the iterator. This is an important distinction when it comes to the two underscore functions, _.reduce and _.reduceRight, that take 'memo' as their third argument -- in the case of these two the index will not be the second argument, but the third:
var destination = (function() {
var fields = ['_333st', 'offroad', 'fbi'];
return _.reduce(waybillInfo.destination.split(','), function(destination, segment, index) {
destination[fields[index]] = segment;
return destination;
}, {});
})();
console.log(destination);
/*
_333st: "NYARFTW TX"
fbi: "FTWUP"
offroad: "UP"
The following is better of course but not demonstrate my point:
var destination = _.object(['_333st', 'offroad', 'fbi'], waybillInfo.destination.split(','));
*/
So if you wanted you could get the index using underscore itself: _.last(_.initial(arguments))
. A possible exception (I haven't tried) is _.map, as it can take an object instead of a list: "If list is a JavaScript object, iterator's arguments will be (value, key, list)." -- see: http://underscorejs.org/#map
When available, I believe that most lodash array functions will show the iteration. But sorting isn't really an iteration in the same way: when you're on the number 66, you aren't processing the fourth item in the array until it's finished. A custom sort function will loop through an array a number of times, nudging adjacent numbers forward or backward, until the everything is in its proper place.
If you'd rather transform your array, then the iterator
parameter of underscore's map
function is also passed the index as a second argument. So:
_.map([1, 4, 2, 66, 444, 9], function(value, index){ return index + ':' + value; });
... returns:
["0:1", "1:4", "2:2", "3:66", "4:444", "5:9"]
You can get the index of the current iteration by adding another parameter to your iterator function
, e.g.
_.each(['foo', 'bar', 'baz'], function (val, i) {
console.log(i + ": " + val); // 0: foo, 1: bar, 2: baz
});
I think it's worth mentioning how the Underscore's _.each() works internally. The _.each(list, iteratee) checks if the passed list is an array object, or an object.
In the case that the list is an array, iteratee arguments will be a list element and index as in the following example:
var a = ['I', 'like', 'pancakes', 'a', 'lot', '.'];
_.each( a, function(v, k) { console.log( k + " " + v); });
0 I
1 like
2 pancakes
3 a
4 lot
5 .
On the other hand, if the list argument is an object the iteratee will take a list element and a key:
var o = {name: 'mike', lastname: 'doe', age: 21};
_.each( o, function(v, k) { console.log( k + " " + v); });
name mike
lastname doe
age 21
For reference this is the _.each() code from Underscore.js 1.8.3
_.each = _.forEach = function(obj, iteratee, context) {
iteratee = optimizeCb(iteratee, context);
var i, length;
if (isArrayLike(obj)) {
for (i = 0, length = obj.length; i < length; i++) {
iteratee(obj[i], i, obj);
}
} else {
var keys = _.keys(obj);
for (i = 0, length = keys.length; i < length; i++) {
iteratee(obj[keys[i]], keys[i], obj);
}
}
return obj;
};
Source: Stackoverflow.com