0

I created an array in Javascript that should be all numbers. When I use Math.max on it, the function returns NaN. I am stumped. First, I know the documentation says Math.max returns NaN when one of the arguments cannot be converted to a number, so I think that is happening. I cannot understand what that is.

Here d is an array of objects. The objects are key-value pairs. I want to put all the values of each object in the d array into one new array and then find the max. Here is how I make my new array valsarr:

var valsarr = [];
d.map(function(row){ 
    Object.keys(row).forEach(function(key) {
        row[key] = Number(row[key]);
        valsarr.push(Number(row[key]));
    });
});

I know using Number twice is redundant, but I added the second to be extra careful. I tried parseInt and + in its place and had the same result. Then I try to obtain the max of that array and print:

var mymax = Math.max.apply(Math, valsarr)
console.log(mymax);

It prints NaN As part of the debugging process, I tried filtering the array to find non-numbers in it, but I get nothing. My code for that task could be faulty too, however. Here it is:

function isNotNumber(value) {
    return (typeof(value) !== "number");
}
var badarr = valsarr.filter(isNotNumber);
console.log('Filtered Array\n', badarr); 

It prints an array of length 0. I believe that means it found no non-number values in the array.

Two more notes: The original data in d contains thousands of values. It comes from .csvs. So I don't want to hunt through all the values to find ones that are not numbers. I can easily see the original d object and the valsarr array do have numbers in them. Second, it works when I load in one of the .csvs I am using but not any of the others.

But again, with any of the .csvs, both d and valsarr have at least some numbers in them when I scan through them to check, so the first code block is doing something, at least every time.

Any help would be greatly appreciated.

7
  • 2
    typeof NaN also returns number. Try to use isNaN(). Commented Feb 16, 2018 at 2:49
  • 1
    post the sample structure of d Commented Feb 16, 2018 at 2:50
  • This will filter non-numbers: valsarr.filter(v => ! isNaN(v)); Commented Feb 16, 2018 at 2:56
  • to find non-numbers use var badarr = valsarr.filter(isNaN) Commented Feb 16, 2018 at 2:56
  • Use d.forEach instead of d.map. Commented Feb 16, 2018 at 3:00

4 Answers 4

2

Math.max takes several arguments, not an array. You can use spread (ES7)

Math.max(...[1,2,3,4])

Or you can use apply:

Math.max.apply(null,[1,2,3,4])

Make sure to take out anything from the array that isn't a number as laxydeveloper suggested:

Math.max.apply(null,array.filter(x=>!isNaN(x))

In your code it would look like this:

var d = [
  {p:"hello"},
  {d:2},
  {q:7},
  {other:1,highest:10},
  {q:7}
];
var highest = Math.max.apply(
  null,
  d.map(
    row=>
      Object.keys(row).map(
        key=>
          Number(row[key])
      )
  ).reduce(//flatten array of arrays [[1,2],[2,3]] to [1,2,3,4]
    (all,item)=>all.concat(item),
    []
  ).filter(//take out all that are not numbers
    x=>!isNaN(x)
  )
);
console.log("highest:",highest);

If you want to know the index and key of the object having the highest value you can do this:

var d = [
  {p:"hello"},
  {d:2},
  {q:7},
  {other:1,highest:10},
  {q:7}
];
//get highest value,index and the key
const [highestVal,highestKey,highestIndex] = d.map(
  (item,index)=>
    Object.keys(item).reduce(
      (all,key)=>all.concat([[item[key],key,index]]),//val,key,index
      []
    )
).reduce(
  (highest,item)=>{
    return item.reduce(
      (highest,[val,key,index])=>{
        return (val>highest[0])
          ? [val,key,index]
          : highest
      },
      highest
    )
  },
  [-Infinity,undefined,undefined]
);
console.log(
  "highest value:",highestVal,
  "highest object",d[highestIndex],
  "highest key of that object:",highestKey
);

Sign up to request clarification or add additional context in comments.

Comments

0

Maybe you could cheat a bit, and try to find the badly behaved value by checking right at the time that you set the value:

Object.keys(row).forEach(function(key) {
    row[key] = +row[key];
    valsarr.push(row[key]);
    if (Math.max(row[key]) !== row[key]) {
        console.log(row);
    }
}

and then you can see the offending row...

Comments

0

you can use filter function for removing NaN from array.

  var valsarr = [];//initialize data in array 
  var result=  valsarr.filter(v => ! isNaN(v));

Comments

0

You should be able to run the Math.max() function on the valsArray that I create in my code below without any problems.

// Your code:
/*var valsarr = [];
d.map(function(row){ 
  // This is what you were doing, but you weren't actually returning anything back to the map function, so you weren't creating anything new on the `d` setup, as well as you weren't assigning the return value of the .map() function to anything.
  Object.keys(row).forEach(function(key) {
    row[key] = Number(row[key]);
    valsarr.push(Number(row[key]));
  });
});*/

// Creating a mock set of data for "d", since you didn't provide it.
var d = [
 { a: '1', b: '2', c: '3' },
 { a: '1', b: '2', c: 'test' }, // This should fail.
 { a: '1', b: '2', c: '3' },
 { a: '1', b: '2', c: '3' },
 { a: '1', b: '2', c: '3' }
]

// This is what I think you are trying to do:

// I am doing this concat.apply() method because the Object.values() inside of the .map() method creates a new Array with the values, so we need to concatenate all of them together 
var valsArray = [].concat.apply([], d.map((row) => {
  return Object.values(row)
    .filter((val) => {
      console.log('Trouble-causing row:', isNaN(parseInt(val)), row, val);
      return !isNaN(parseInt(val));
    })
    .map((val) => parseInt(val))
}));

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.