Is JavaScript map function broken [duplicate] - javascript

From the Mozilla Developer Network:
[1,4,9].map(Math.sqrt)
will yield:
[1,2,3]
Why then does this:
['1','2','3'].map(parseInt)
yield this:
[1, NaN, NaN]
I have tested in Firefox 3.0.1 and Chrome 0.3 and just as a disclaimer, I know this is not cross-browser functionality (no IE).
I found out that the following will accomplish the desired effect. However, it still doesn’t explain the errant behavior of parseInt.
['1','2','3'].map(function(i){return +i;}) // returns [1,2,3]

The callback function in Array.map has three parameters:
From the same Mozilla page that you linked to:
callback is invoked with three arguments: the value of the element, the index of the element, and the Array object being traversed."
So if you call a function parseInt which actually expects two arguments, the second argument will be the index of the element.
In this case, you ended up calling parseInt with radix 0, 1 and 2 in turn. The first is the same as not supplying the parameter, so it defaulted based on the input (base 10, in this case). Base 1 is an impossible number base, and 3 is not a valid number in base 2:
parseInt('1', 0); // OK - gives 1
parseInt('2', 1); // FAIL - 1 isn't a legal radix
parseInt('3', 2); // FAIL - 3 isn't legal in base 2
So in this case, you need the wrapper function:
['1','2','3'].map(function(num) { return parseInt(num, 10); });
or with ES2015+ syntax:
['1','2','3'].map(num => parseInt(num, 10));
(In both cases, it's best to explicitly supply a radix to parseInt as shown, because otherwise it guesses the radix based on the input. In some older browsers, a leading 0 caused it to guess octal, which tended to be problematic. It will still guess hex if the string starts with 0x.)

map is passing along a 2nd argument, which is (in many of the cases) messing up parseInt's radix parameter.
If you're using underscore you can do:
['10','1','100'].map(_.partial(parseInt, _, 10))
Or without underscore:
['10','1','100'].map(function(x) { return parseInt(x, 10); });

You could solve this problem using Number as iteratee function:
var a = ['0', '1', '2', '10', '15', '57'].map(Number);
console.log(a);
Without the new operator, Number can be used to perform type conversion. However, it differs from parseInt: it doesn't parse the string and returns NaN if the number cannot be converted. For instance:
console.log(parseInt("19asdf"));
console.log(Number("19asf"));

I'm going to wager that it's something funky going on with the parseInt's 2nd parameter, the radix. Why it is breaking with the use of Array.map and not when you call it directly, I do not know.
// Works fine
parseInt( 4 );
parseInt( 9 );
// Breaks! Why?
[1,4,9].map( parseInt );
// Fixes the problem
[1,4,9].map( function( num ){ return parseInt( num, 10 ) } );

You can use arrow function ES2015/ES6 and just pass number to the parseInt. Default value for radix will be 10
[10, 20, 30].map(x => parseInt(x))
Or you can explicitly specify radix for better readability of your code.
[10, 20, 30].map(x => parseInt(x, 10))
In example above radix explicitly set to 10

another (working) quick fix :
var parseInt10 = function(x){return parseInt(x, 10);}
['0', '1', '2', '10', '15', '57'].map(parseInt10);
//[0, 1, 2, 10, 15, 57]

You can solve that issue like this:
array.map(x => parseInt(x))
Example:
var arr = ["3", "5", "7"];
console.log(
arr.map(x => parseInt(x))
);

parseInt IMHO should be avoided for this very reason. You can wrap it to make it more safe in these contexts like this:
const safe = {
parseInt: (s, opt) => {
const { radix = 10 } = opt ? opt : {};
return parseInt(s, radix);
}
}
console.log( ['1','2','3'].map(safe.parseInt) );
console.log(
['1', '10', '11'].map(e => safe.parseInt(e, { radix: 2 }))
);
lodash/fp caps iteratee arguments to 1 by default to avoid these gotchas. Personally I have found these workarounds to create as many bugs as they avoid. Blacklisting parseInt in favor of a safer implementation is, I think, a better approach.

Related

Why does the following shorthand not work in JS? [duplicate]

From the Mozilla Developer Network:
[1,4,9].map(Math.sqrt)
will yield:
[1,2,3]
Why then does this:
['1','2','3'].map(parseInt)
yield this:
[1, NaN, NaN]
I have tested in Firefox 3.0.1 and Chrome 0.3 and just as a disclaimer, I know this is not cross-browser functionality (no IE).
I found out that the following will accomplish the desired effect. However, it still doesn’t explain the errant behavior of parseInt.
['1','2','3'].map(function(i){return +i;}) // returns [1,2,3]
The callback function in Array.map has three parameters:
From the same Mozilla page that you linked to:
callback is invoked with three arguments: the value of the element, the index of the element, and the Array object being traversed."
So if you call a function parseInt which actually expects two arguments, the second argument will be the index of the element.
In this case, you ended up calling parseInt with radix 0, 1 and 2 in turn. The first is the same as not supplying the parameter, so it defaulted based on the input (base 10, in this case). Base 1 is an impossible number base, and 3 is not a valid number in base 2:
parseInt('1', 0); // OK - gives 1
parseInt('2', 1); // FAIL - 1 isn't a legal radix
parseInt('3', 2); // FAIL - 3 isn't legal in base 2
So in this case, you need the wrapper function:
['1','2','3'].map(function(num) { return parseInt(num, 10); });
or with ES2015+ syntax:
['1','2','3'].map(num => parseInt(num, 10));
(In both cases, it's best to explicitly supply a radix to parseInt as shown, because otherwise it guesses the radix based on the input. In some older browsers, a leading 0 caused it to guess octal, which tended to be problematic. It will still guess hex if the string starts with 0x.)
map is passing along a 2nd argument, which is (in many of the cases) messing up parseInt's radix parameter.
If you're using underscore you can do:
['10','1','100'].map(_.partial(parseInt, _, 10))
Or without underscore:
['10','1','100'].map(function(x) { return parseInt(x, 10); });
You could solve this problem using Number as iteratee function:
var a = ['0', '1', '2', '10', '15', '57'].map(Number);
console.log(a);
Without the new operator, Number can be used to perform type conversion. However, it differs from parseInt: it doesn't parse the string and returns NaN if the number cannot be converted. For instance:
console.log(parseInt("19asdf"));
console.log(Number("19asf"));
I'm going to wager that it's something funky going on with the parseInt's 2nd parameter, the radix. Why it is breaking with the use of Array.map and not when you call it directly, I do not know.
// Works fine
parseInt( 4 );
parseInt( 9 );
// Breaks! Why?
[1,4,9].map( parseInt );
// Fixes the problem
[1,4,9].map( function( num ){ return parseInt( num, 10 ) } );
You can use arrow function ES2015/ES6 and just pass number to the parseInt. Default value for radix will be 10
[10, 20, 30].map(x => parseInt(x))
Or you can explicitly specify radix for better readability of your code.
[10, 20, 30].map(x => parseInt(x, 10))
In example above radix explicitly set to 10
another (working) quick fix :
var parseInt10 = function(x){return parseInt(x, 10);}
['0', '1', '2', '10', '15', '57'].map(parseInt10);
//[0, 1, 2, 10, 15, 57]
You can solve that issue like this:
array.map(x => parseInt(x))
Example:
var arr = ["3", "5", "7"];
console.log(
arr.map(x => parseInt(x))
);
parseInt IMHO should be avoided for this very reason. You can wrap it to make it more safe in these contexts like this:
const safe = {
parseInt: (s, opt) => {
const { radix = 10 } = opt ? opt : {};
return parseInt(s, radix);
}
}
console.log( ['1','2','3'].map(safe.parseInt) );
console.log(
['1', '10', '11'].map(e => safe.parseInt(e, { radix: 2 }))
);
lodash/fp caps iteratee arguments to 1 by default to avoid these gotchas. Personally I have found these workarounds to create as many bugs as they avoid. Blacklisting parseInt in favor of a safer implementation is, I think, a better approach.

How to identify any string?

An array shows 3 numbers randomly, and I had to write a code that sums the 3 numbers, but the array has a trick to sometimes show a string:
[96, ".!asd", 182]
["##$%", 5, 43]
[64, "bd", 48]
I would like to use an "if" that would return "not valid" if there's a string in the array.
if (...){
return not valid
}
Please, if there's a way to identify any string, could you tell me the code?
You can use Array.prototype.some() to see if your array contains NaN's
var x = [96, ".!asd", 182]
var y = [96, 1000, 182]
console.log(x.some(isNaN))
console.log(y.some(isNaN))
You should use the isNaN function as it is explained here : Is there a (built-in) way in JavaScript to check if a string is a valid number?
isNaN(123) // false
isNaN('123') // false
isNaN('1e10000') // false (This translates to Infinity, which is a number)
isNaN('foo') // true
isNaN('10px') // true
You can use isNaN to determine if a stirng is a number
isNaN('123') //false
isNaN('Hello') //true
Use the object Number:
if (Number.isNaN(+element_in_array)) return "Not Valid!!"
function sum(array) {
if (array.some((n) => Number.isNaN(+n))) {
return "Invalid data, at least one element is not a number.";
}
return array.reduce((a, n) => a + Number(n), 0);
}
console.log(sum([96, ".!asd", 182]))
console.log(sum(["##$%", 5, 43]))
console.log(sum([64, "bd", 48]))
console.log(sum([64, 44, 48]))
You could use NaN to determine if all elements are numbers by using an unary plus to convert the string to number. If succeed, you get a number for summing, if not then NaN is returned and summed. A single NaN spoils the result and the result is NaN.
function not(fn) {
return function (v) {
return !fn(v);
};
}
function sum(array) {
return array.reduce((a, b) => +a + +b);
}
console.log([[96, ".!asd", 182], ["##$%", 5, 43], [64, "bd", 48], [2, 3, 5]].map(sum).filter(not(isNaN)));
try using typeof to validate wether or not you are dealing with a string.mdn typeof
You can use if type(x) == str to check if a variable x is of type String. It is a built-in function. Please refer to official python documentation to know more.
https://docs.python.org/3/library/functions.html#type

Bug or feature parsing with map function an array from string to integer on Javascript [duplicate]

From the Mozilla Developer Network:
[1,4,9].map(Math.sqrt)
will yield:
[1,2,3]
Why then does this:
['1','2','3'].map(parseInt)
yield this:
[1, NaN, NaN]
I have tested in Firefox 3.0.1 and Chrome 0.3 and just as a disclaimer, I know this is not cross-browser functionality (no IE).
I found out that the following will accomplish the desired effect. However, it still doesn’t explain the errant behavior of parseInt.
['1','2','3'].map(function(i){return +i;}) // returns [1,2,3]
The callback function in Array.map has three parameters:
From the same Mozilla page that you linked to:
callback is invoked with three arguments: the value of the element, the index of the element, and the Array object being traversed."
So if you call a function parseInt which actually expects two arguments, the second argument will be the index of the element.
In this case, you ended up calling parseInt with radix 0, 1 and 2 in turn. The first is the same as not supplying the parameter, so it defaulted based on the input (base 10, in this case). Base 1 is an impossible number base, and 3 is not a valid number in base 2:
parseInt('1', 0); // OK - gives 1
parseInt('2', 1); // FAIL - 1 isn't a legal radix
parseInt('3', 2); // FAIL - 3 isn't legal in base 2
So in this case, you need the wrapper function:
['1','2','3'].map(function(num) { return parseInt(num, 10); });
or with ES2015+ syntax:
['1','2','3'].map(num => parseInt(num, 10));
(In both cases, it's best to explicitly supply a radix to parseInt as shown, because otherwise it guesses the radix based on the input. In some older browsers, a leading 0 caused it to guess octal, which tended to be problematic. It will still guess hex if the string starts with 0x.)
map is passing along a 2nd argument, which is (in many of the cases) messing up parseInt's radix parameter.
If you're using underscore you can do:
['10','1','100'].map(_.partial(parseInt, _, 10))
Or without underscore:
['10','1','100'].map(function(x) { return parseInt(x, 10); });
You could solve this problem using Number as iteratee function:
var a = ['0', '1', '2', '10', '15', '57'].map(Number);
console.log(a);
Without the new operator, Number can be used to perform type conversion. However, it differs from parseInt: it doesn't parse the string and returns NaN if the number cannot be converted. For instance:
console.log(parseInt("19asdf"));
console.log(Number("19asf"));
I'm going to wager that it's something funky going on with the parseInt's 2nd parameter, the radix. Why it is breaking with the use of Array.map and not when you call it directly, I do not know.
// Works fine
parseInt( 4 );
parseInt( 9 );
// Breaks! Why?
[1,4,9].map( parseInt );
// Fixes the problem
[1,4,9].map( function( num ){ return parseInt( num, 10 ) } );
You can use arrow function ES2015/ES6 and just pass number to the parseInt. Default value for radix will be 10
[10, 20, 30].map(x => parseInt(x))
Or you can explicitly specify radix for better readability of your code.
[10, 20, 30].map(x => parseInt(x, 10))
In example above radix explicitly set to 10
another (working) quick fix :
var parseInt10 = function(x){return parseInt(x, 10);}
['0', '1', '2', '10', '15', '57'].map(parseInt10);
//[0, 1, 2, 10, 15, 57]
You can solve that issue like this:
array.map(x => parseInt(x))
Example:
var arr = ["3", "5", "7"];
console.log(
arr.map(x => parseInt(x))
);
parseInt IMHO should be avoided for this very reason. You can wrap it to make it more safe in these contexts like this:
const safe = {
parseInt: (s, opt) => {
const { radix = 10 } = opt ? opt : {};
return parseInt(s, radix);
}
}
console.log( ['1','2','3'].map(safe.parseInt) );
console.log(
['1', '10', '11'].map(e => safe.parseInt(e, { radix: 2 }))
);
lodash/fp caps iteratee arguments to 1 by default to avoid these gotchas. Personally I have found these workarounds to create as many bugs as they avoid. Blacklisting parseInt in favor of a safer implementation is, I think, a better approach.

Arrary map strange behavor [duplicate]

From the Mozilla Developer Network:
[1,4,9].map(Math.sqrt)
will yield:
[1,2,3]
Why then does this:
['1','2','3'].map(parseInt)
yield this:
[1, NaN, NaN]
I have tested in Firefox 3.0.1 and Chrome 0.3 and just as a disclaimer, I know this is not cross-browser functionality (no IE).
I found out that the following will accomplish the desired effect. However, it still doesn’t explain the errant behavior of parseInt.
['1','2','3'].map(function(i){return +i;}) // returns [1,2,3]
The callback function in Array.map has three parameters:
From the same Mozilla page that you linked to:
callback is invoked with three arguments: the value of the element, the index of the element, and the Array object being traversed."
So if you call a function parseInt which actually expects two arguments, the second argument will be the index of the element.
In this case, you ended up calling parseInt with radix 0, 1 and 2 in turn. The first is the same as not supplying the parameter, so it defaulted based on the input (base 10, in this case). Base 1 is an impossible number base, and 3 is not a valid number in base 2:
parseInt('1', 0); // OK - gives 1
parseInt('2', 1); // FAIL - 1 isn't a legal radix
parseInt('3', 2); // FAIL - 3 isn't legal in base 2
So in this case, you need the wrapper function:
['1','2','3'].map(function(num) { return parseInt(num, 10); });
or with ES2015+ syntax:
['1','2','3'].map(num => parseInt(num, 10));
(In both cases, it's best to explicitly supply a radix to parseInt as shown, because otherwise it guesses the radix based on the input. In some older browsers, a leading 0 caused it to guess octal, which tended to be problematic. It will still guess hex if the string starts with 0x.)
map is passing along a 2nd argument, which is (in many of the cases) messing up parseInt's radix parameter.
If you're using underscore you can do:
['10','1','100'].map(_.partial(parseInt, _, 10))
Or without underscore:
['10','1','100'].map(function(x) { return parseInt(x, 10); });
You could solve this problem using Number as iteratee function:
var a = ['0', '1', '2', '10', '15', '57'].map(Number);
console.log(a);
Without the new operator, Number can be used to perform type conversion. However, it differs from parseInt: it doesn't parse the string and returns NaN if the number cannot be converted. For instance:
console.log(parseInt("19asdf"));
console.log(Number("19asf"));
I'm going to wager that it's something funky going on with the parseInt's 2nd parameter, the radix. Why it is breaking with the use of Array.map and not when you call it directly, I do not know.
// Works fine
parseInt( 4 );
parseInt( 9 );
// Breaks! Why?
[1,4,9].map( parseInt );
// Fixes the problem
[1,4,9].map( function( num ){ return parseInt( num, 10 ) } );
You can use arrow function ES2015/ES6 and just pass number to the parseInt. Default value for radix will be 10
[10, 20, 30].map(x => parseInt(x))
Or you can explicitly specify radix for better readability of your code.
[10, 20, 30].map(x => parseInt(x, 10))
In example above radix explicitly set to 10
another (working) quick fix :
var parseInt10 = function(x){return parseInt(x, 10);}
['0', '1', '2', '10', '15', '57'].map(parseInt10);
//[0, 1, 2, 10, 15, 57]
You can solve that issue like this:
array.map(x => parseInt(x))
Example:
var arr = ["3", "5", "7"];
console.log(
arr.map(x => parseInt(x))
);
parseInt IMHO should be avoided for this very reason. You can wrap it to make it more safe in these contexts like this:
const safe = {
parseInt: (s, opt) => {
const { radix = 10 } = opt ? opt : {};
return parseInt(s, radix);
}
}
console.log( ['1','2','3'].map(safe.parseInt) );
console.log(
['1', '10', '11'].map(e => safe.parseInt(e, { radix: 2 }))
);
lodash/fp caps iteratee arguments to 1 by default to avoid these gotchas. Personally I have found these workarounds to create as many bugs as they avoid. Blacklisting parseInt in favor of a safer implementation is, I think, a better approach.

looking for alternative way to do isNaN test

I'm looking for an alternative way to do an isNaN test
My original code looked like this. The code works, but I noticed that num1 changes type, which is ugly
// example 1: num1 changes type
num1 = parseInt(str1, 10);
if isNaN(num1){num1=-1;}
I changed it to this, but this one uses duplicate code
// example 2: duplicate code
if (isNaN(parseInt(str1,10))){num1=-1;}
else {num1=parseInt(str1,10);}
At first I was thinking about adding an extra variable to store parseInt(str1,10) but that variable will change type, too and is therefore in effect the same as example 1.
Is there an alternative to example 1 or 2?
by changes type I mean this
console.log(typeof(isNaN("123"))); // boolean
console.log(typeof(isNaN("abc"))); // boolean
console.log(typeof(parseInt("123", 10))); // number
console.log(typeof(parseInt("abc", 10))); // number
.
console.log(typeof(Number("123"))); // number
console.log(typeof(Number("abc"))); // number
console.log(Number("123")); // 123
console.log(Number("abc")); // NaN
First, I would suggest that parseInt() isn't the best choice. For example:
var x = parseInt("123hello world how are you today?", 10);
will set "x" to 123 and simply ignore the trailing garbage.
You could set up a functional way to do this, if you really wanted to avoid the intermediate temporary value:
function ifNumeric( s, f ) {
s = +s;
if (!isNaN(s)) f(s);
}
ifNumeric( someString, function( n ) { /* whatever, with "n" being a number */ } );
but that seems a little extreme. But anyway note that in that example the + operator is used to coerce the value of the variable to the "number" type. You could alternatively use the "Number" constructor, but not as a constructor:
var numeric = Number( someString );
Either of those will give you a NaN if the string isn't a completely valid number without trailing garbage.
edit — if you just want a safe "give me a number" converter:
function toNumber( value, ifGarbage ) {
value = +value;
return isNaN(value) ? ifGarbage : value;
}
var num1 = toNumber( str1, -1 );

Categories

Resources