-3

I am trying to transform all values in a 2D array from strings to numbers, except values that are actually strings (within the Javascript Excel Add-in API)

Example:

[["1000"],["3.2"],["banana"]]

to

[[1000],[3.2],["banana]]

"1000" -> 1000
"3.2" -> 3.2
"banana" -> "banana"

4 Answers4

0

You can create a helper function where you use your own rules to determine whether a string is a number or not:

function asNumberIfPossible (str) {
  if (str === '') return str;
  const n = Number(str);
  return Number.isNaN(n) ? str : n;
}

const examples = [
  '1000',
  '3.2',
  'banana',
  '0',
  '',
  '1.2e5',
  '0xfff',
  '0b101',
  ' 0',
  '0 ',
  '0 1',
  '15px',
  '28.5px',
];

for (const str of examples) {
  const result = asNumberIfPossible(str);
  console.log(
    typeof result,
    JSON.stringify(str),
    '->',
    JSON.stringify(result),
  );
}

Note that using the Number() constructor to coerce strings is more strict than using parseInt() or parseFloat(). When using parseFloat(), for example, the string "28.5px" becomes the number 28.5, but using the Number() constructor to coerce the string will result in NaN. This strictness is desirable in my opinion because it prevents a loss of information during the coercion:

const str = '28.5px';

console.log('parseFloat:', parseFloat(str));
console.log('Number:', Number(str));
jsejcksn
  • 27,667
  • 4
  • 38
  • 62
0

This function will help you solve the problem:

var values = ['1000','3.2','banana'];

function stringToNumber(arrayOfValues) {
  for (var i = 0; i < arrayOfValues.length; i++) {
    if (typeof arrayOfValues[i] != 'string' || isNaN(arrayOfValues[i])) {
      continue;
    }
    arrayOfValues[i] = +arrayOfValues[i];  // + before a string converts it to number
  }
}

Update:

In the comment below, you wrote you receive a nested array from Excel, so I wrote a recursive function for you:

var arrayOfArrays = [
  ['1000','3.2','banana'], 
  ['2','value','1820','just a word', true], 
  [20]
]; 

var values = ['1000','3.2','banana']; 

function stringToNumber(arrayOfValues) { 
  for (var i = 0; i < arrayOfValues.length; i++) { 
    if (typeof arrayOfValues[i] == 'object') {
      stringToNumber(arrayOfValues[i]); continue;
    }
    if (typeof arrayOfValues[i] != 'string' || isNaN(arrayOfValues[i])) {
      continue;
    }
    arrayOfValues[i] = +arrayOfValues[i]; // + before a string converts it to number
  }
}

Try it out!

Fillyjonk
  • 178
  • 1
  • 1
  • 7
  • I'm not sure if this would work because I'm working with an array of arrays. An excel table of this format `line1 -> 1 2 3; line2 -> 4 5 6; line3 -> 7 8 9` returns `[[1,2,3],[4,5,6],[7,8,9]]` – Francisco Barroca Sep 18 '22 at 14:41
  • Just loop through the array of arrays to make it work. You might want to use recursion if you do not know the depth of the nested array. The principle described in the code above will work here. – Fillyjonk Sep 18 '22 at 20:38
  • @FranciscoBarroca , I updated my response and added a recursive function for you to handle nested arrays. Good luck! – Fillyjonk Sep 20 '22 at 17:19
  • Hello @Fillyjonk ! Thank you so much! I don't know why but I tried your code and I did console.log(stringToNumber(arrayOfArrays)); and it returns "Undefined) – Francisco Barroca Sep 20 '22 at 20:43
  • @FranciscoBarroca , this is because the function is a void function, i.e. it does not return anything, it only modifies your existing array. The following works: 1) stringToNumber(arrayOfArrays); 2) stringToNumber(values); 3) console.log(arrayOfArrays); 4) console.log(values); – Fillyjonk Sep 20 '22 at 22:03
0

Just use the unary plus operator. Any string can be turned into a number using it, as long as the string is exclusively a number.

var x = +”1000”; // results in 1000
var y = +”Hi” // NaN
Dan Mullin
  • 4,285
  • 2
  • 18
  • 34
-1

You can check if the value is greater than -1 and Math.abs to convert the negative to positive, if the condition is true then the value is a number, and if not it's a string.

if(Math.abs(value) > -1) {
    // value is a number
  } else {
    // value is not a number
  }