Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Getting NaN inconsistently mapping parseInt

Tags:

Was playing around with some code to create an array of 0's and found that for only one value NaN was returned instead of 0. I get this in Chrome, Node, and Firefox.

What's causing the second value to be NaN?

var arr = new Array(32).join(0).split('').map(parseInt)
// prints [0, NaN, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
console.dir(arr)
like image 523
11 revs, 3 users 72% Avatar asked Sep 01 '15 01:09

11 revs, 3 users 72%


People also ask

Why 1 7 11 map parseInt returns 1 NaN 3 in JavaScript?

['1', '7', '11']. map(parseInt) doesn't work as intended because map passes three arguments into parseInt() on each iteration. The second argument index is passed into parseInt as a radix parameter. So, each string in the array is parsed using a different radix.

Why am I getting Nan in Javascript?

Nan means “Not a number”, this is because inside your cube function, you're not calling the square function, but getting it's contents. Change return x * square; with return x * square(x); and it should work.


3 Answers

That's because the function passed to map will be called with three arguments:

  1. The current array item
  2. The index of that item
  3. The whole array

In this case, that function is parseInt, which only uses two arguments:

  1. The string to be parsed
  2. The radix used to parse the string
  3. Additional arguments will be ignored.

Therefore, for the 2nd item in the array (i.e. index 1), the call will be

parseInt("0", 1, ignoredArray)

When the radix is 1, NaN is returned:

  • Let R = ToInt32(radix).
  • If R ≠ 0, then
    • If R < 2 or R > 36, then return NaN.

Also note that if you used a bigger number like new Array(99), you would have seen NaNs starting at index 37.

like image 69
Oriol Avatar answered Sep 25 '22 02:09

Oriol


The .map() function passes three arguments to the callback of which two are used by parseInt(): the value, and the index (the third is the array itself). When the index is 1, any string of digits will be an invalid value. The parseInt() function ignores the second argument when it's 0.

To elaborate: for the first element, parseInt() is called like this:

parseInt("0", 0)

because the array value is zero and the index is zero. On the second call, it's this:

parseInt("0", 1)

and that returns NaN.

Note that if you're not too picky about the results being all integers, you can do what you're trying to do with the Number constructor:

var arr = new Array(32).join(0).split('').map(Number);

In ES2015 (the newest ratified standard for JavaScript, which if we are all very good will be fully implemented in all browsers as our Christmas present) you can use the .fill() function:

var arr = new Array(31).fill(0);
like image 42
Pointy Avatar answered Sep 23 '22 02:09

Pointy


The mapping passes three arguments to its function:

  • the element;
  • the index of that element within the array; and
  • the array itself.

The parseInt function will look at the first two of those, treating the first correctly as the string but treating the second as the base to use. When the base is neither zero nor in the inclusive range 2..36, it returns NaN (1). If you had an array with forty elements, you'd also see a bunch of NaN values at the end:

0, NaN, 0, 0, 0, ... 0, 0, 0, NaN, NaN

You'd also get some pretty strange results if the number strings were anything other than zero, since the array index would dictate what base was used to interpret it.

To actually fix this, you can just provide a function that will translate what map gives you to what parseInt expects (a map map, I guess you could call it):

function myParseInt(s,r,a) { return parseInt(s,10); }
var arr = new Array(32).join(0).split('').map(myParseInt)
alert(arr)

You might also want to have a look at the way you're creating this array, it will actually end up as an array of size 31 rather than 32. If you just want an array of '0' characters, you can just use:

var arr = new Array(32).fill('0')

assuming you have a browser that supports ECMAScript 2015, which is Safari, Firefox and Chrome-desktop as of the time of this answer.


(1) A base of zero is the default case for handling things like hex prefixes.

A base of one makes no sense in a purely positional system (where each digit is multiplied by a power of the base and accumulated) since the only allowed digit there would be 0, so each place value would be that zero multiplied by 1n. In other words, the only number possible in a base-one system would be zero.

Bases from 2 to 36 are therefore more sensible.

like image 30
paxdiablo Avatar answered Sep 24 '22 02:09

paxdiablo