Reputation: 5039
I need to process some arrays that contains undefined
values, like the following:
[ 1, 1, 1, 1, 1, , 1, 1 ]
[ 1, , 1, , , 1, 1 ]
[ 1, , , , , 1, 1 ]
What I need to achieve is not a removal of the undefined
values, but I need to replace them with zeros.
I tried to use underscore.js to achieve this; without success.
The following is my solution attempt:
binarymap = _.map(binarymap, function(curr){
// let's replace all undefined with 0s
if(_.isUndefined(curr)) {
return 0;
}
return curr;
});
Unfortunately, it does not work. underscore.js's function _.map
totally ignores undefined
values.
Any ideas? Elegant solutions?
Upvotes: 3
Views: 8146
Reputation: 20616
Maybe something changed since this was posted, but both underscore (v1.8.3) and lodash (v4.13.1) handle this quite well:
var u = [1, , , , , 1, 1];
_.map(u, function(n) { return n || 0; });
// [1, 0, 0, 0, 0, 1, 1]
Native loops skip undefined entries because they explicitly only loop over defined elements of an array (ref). The source array doesn't contain undefined
elements, it contains elements which were never defined at all.
These arrays are different:
[1, undefined, 1]
[1, , 1]
The first array defines its first index as undefined
.
The second array does not define the first index at all.
Both have a length of 3.
This feels like it's starting to go off into the WAT fringes, but it's a subtle difference worth knowing.
Since we're in the weeds already, there is a convoluted native solution I'd never use in real life:
var u = [1, , , , , 1, 1];
Array(u.length).join(0).split('').map(function(n, i) { return u[i] || 0; })
// [1, 0, 0, 0, 0, 1, 1]
Array(u.length).join(0).split('')
yields a dummy array of arbitrary strings which can then be mapped over. The map function references the original array by index, then uses a simple boolean switch to return defined values or zero.
Upvotes: 2
Reputation: 239623
The actual problem here is the missing array elements,
Array elements may be elided at the beginning, middle or end of the element list. Whenever a comma in the element list is not preceded by an AssignmentExpression (i.e., a comma at the beginning or after another comma), the missing array element contributes to the length of the Array and increases the index of subsequent elements. Elided array elements are not defined. If an element is elided at the end of an array, that element does not contribute to the length of the Array.
And Array.prototype.map
skips all the missing array elements,
callbackfn is called only for elements of the array which actually exist; it is not called for missing elements of the array.
So, in order to make the Array elements to be considered by the map
function, the simplest way I could think of is to tweak your approach a little bit, like this
var arr = [ 1, , , , , 1, 1 ];
console.log(_.map(Array.apply(null, arr), function (currentItem) {
return _.isUndefined(currentItem) ? 0 : currentItem;
}));
# [ 1, 0, 0, 0, 0, 1, 1 ]
Here, Array.apply
(which is actually Function.prototype.apply
) does the important thing, converting the missing elements to undefined
.
console.log(Array.apply(null, arr));
# [ 1, undefined, undefined, undefined, undefined, 1, 1 ]
Upvotes: 4
Reputation: 63569
If you wanted to you could add the function as a mixin for use in an underscore chain. Improvised from here.
_.mixin({
dothis: function(obj, interceptor, context) {
return interceptor.call(context, obj);
}
});
function resetArray(arr) {
for (var i = 0, l = arr.length; i < l; i++) {
if (arr[i] === undefined) arr[i] = 0;
}
return arr;
}
var arr = [ 1, , , , , 1, 1 ];
_(arr)
.chain()
.dothis(resetArray)
.tap(console.log) // [1, 0, 0, 0, 0, 1, 1]
Edit: actually, there's a simpler way of doing that:
_.mixin({
resetArray: function (arr) {
for (var i = 0, l = arr.length; i < l; i++) {
if (arr[i] === undefined) arr[i] = 0;
}
return arr;
}
});
var arr = [1, , , , , 1, 1];
_(arr)
.chain()
.resetArray()
.tap(console.log)
Upvotes: 0
Reputation: 4511
If all you need is to remove empty elements from the array, you don't need to use underscore, just iterate over the array removing empty elements with splice
.
You could add that feature prototyping Array class in javascript:
var array = [ 1, 1, , , , , 1, 1 ];
Array.prototype.replaceEmptyElements = function(value) {
for (var i = 0; i < this.length; i++) {
if (typeof this[i] == "undefined") {
this[i] = value;
}
}
return this;
};
var val = //your value
array.replaceEmptyElements(val);
Upvotes: 0
Reputation: 3849
Is this what you mean..?
var arr = [ 1, , , , , 1, 1 ];
for( var i = 0; i < arr.length; i++ ) {
if( typeof(arr[i])==="undefined" ) {
arr[i] = 9;
}
}
console.log( arr );
// yields [1, 9, 9, 9, 9, 1, 1]
Upvotes: 2