4

What I'm trying to achieve is to create a formatted number with thousands-delimiter from a simple string input. So my input would look something like let input = "12345" and my expected return value should look like "12,345".

I know there are already several libraries, which take care of this, but I want to keep it simple and just do it by myself. My current solution is a bit redundant (because of the double .reverse()) and I'm pretty sure, that there is a better solution.

let array = input.split('');

array.reverse();

for (let i = 3; i < array.length; i += 4) {
    array.splice(i, 0, ',');
}

array.reverse();

return array.join('');
mecograph
  • 694
  • 10
  • 20
  • 6
    No need for a library or a home-grown solution. Every current browser supports [`Number.prototype.toLocaleString`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/toLocaleString). – str Jan 07 '19 at 15:19
  • If you want to roll your own concisely, at the expense of readability for some ... https://stackoverflow.com/a/2901298/294949 – danh Jan 07 '19 at 15:20
  • 2
    Number("12345").toLocaleString(); – Ana Liza Pandac Jan 07 '19 at 15:21
  • If you want to roll you own anyway, you could decrement through the original array, instead of incrementing through a reversed array. – Phil Jan 07 '19 at 15:22
  • 1
    `input.toLocaleString('en-US')`. Specify the `en-US` for a 1000's separator. Number representation in `en-IN`, for example, is different – Mortz Jan 07 '19 at 15:27
  • thanks to @str and @ana-liza-pandac, your suggested solutions were exactly what I was looking for! But just out of pure curiosity I would like to know, if there would be a solution to achieve this on an array (e.g. with `.map` or `.reduce`). Also shout out to @mortz for the hint with the parameter! – mecograph Jan 07 '19 at 15:56
  • Yes, you can use `.map` with `toLocaleString`. – str Jan 07 '19 at 16:21
  • 1
    `(e.g. with .map or .reduce).` You could do -> `input.split("").map((m,i) => (a.length - i) % 3 === 0 && (i > 0) ? "," + m : m).join("")` – Keith Jan 07 '19 at 16:22

6 Answers6

2

I have made a similar answer for another question: Insert new element after each nt-h array elements. It is a generalized method that insert a token every N positions. The solution uses a while loop with the Array.splice() method. To meet your request, I have extended it to support start the inserts from the end of the array. Just another option...

let insertTokenEveryN = (arr, token, n, fromEnd) => {

    // Clone the received array, so we don't mutate the
    // original one. You can ignore this if you don't mind.

    let a = arr.slice(0);
    
    // Insert the <token> every <n> elements.

    let idx = fromEnd ? a.length - n : n;

    while ((fromEnd ? idx >= 1 : idx <= a.length))
    {
        a.splice(idx, 0, token);
        idx = (fromEnd  ? idx - n : idx + n + 1);
    }

    return a;
};

let array = Array.from("1234567890");
let res1 = insertTokenEveryN(array, ",", 3, true);
console.log(res1.join(""));
.as-console {background-color:black !important; color:lime;}
.as-console-wrapper {max-height:100% !important; top:0;}

But, obviously, like people commented, your best option for this will be using input.toLocaleString('en-US'):

let input = "1234567890";
console.log(Number(input).toLocaleString("en-US"));
.as-console {background-color:black !important; color:lime;}
.as-console-wrapper {max-height:100% !important; top:0;}
Shidersz
  • 16,846
  • 2
  • 23
  • 48
1

Although in your example the you finish with a string, the title says "into array". This is quite a compact way using lodash:

import { chunk, flatten } from 'lodash'

const ADD_EVERY = 5
const ITEM_TO_ADD = {}

const data = flatten(
  chunk(input, ADD_EVERY).map((section) => 
  section.length === ADD_EVERY ? [...section, ITEM_TO_ADD] : section
)

It is conceptually kind of similar to doing a split().join()

James Trickey
  • 1,322
  • 13
  • 21
0

You could replace by looking for a group of three characters to the end of the string.

var string = '12345678';

console.log(string.replace(/(?=(...)+$)/g, ','));
Nina Scholz
  • 376,160
  • 25
  • 347
  • 392
0

Here is a plain soluce but regex is better.

function separate(str, separator) {
  // Handling the head case (from 0 to 2 size)
  const headSize = str.length % 3;
  
  let newFormat = headSize ? `${str.substr(0, headSize)}${separator}` : '';
  
  // Handle every 3 character
  const nbTripleChar = (str.length - headSize) / 3;

  for (let i = 0; i < nbTripleChar; i += 1) {
     newFormat = `${newFormat}${str.substr((i * 3) + headSize, 3)}`;
     
     if ((i + 1) !== nbTripleChar) {
       newFormat = `${newFormat}${separator}`;
     }
  }
  
  return newFormat;
}

console.log(separate('12515', ','));
Orelsanpls
  • 22,456
  • 6
  • 42
  • 69
0

You can iterate backwards through the array and build the string using a second index. The string concatenation might be costly but it only iterates the list once. You could also probably us .reduce() to do that without a for loop(since almost any array-iteration operation can be done as a function call these days);

let input = 123456789949949291;
let array = input.toString().split('');
let candidateString = '';


for (let i = array.length-1; i >=0; i--) {
    candidateString=array[i]+candidateString;
    let revIndex=array.length-i;
    if(revIndex%3==0 && revIndex!== array.length){
      candidateString = ','+candidateString;
    }
}

console.log(candidateString);
0

If you are not a fan of Regex. or builtins like toLocaleString() this should handle most cases you might encounter

function format(str) {
  str = str.trim().replace(/\s+/g, '')
  if (isNaN(str)) return 'NaN'
  str = str.split('')
  let strBuild = [str.pop()]
  for (let number of strBuild) {
    if (strBuild.length % 3 === 0) strBuild.unshift(str.pop() + ',')
    else strBuild.unshift(str.pop())
    if (!str.length) return strBuild.join('');
  }
}
console.log(format('1 '))
console.log(format('1 a 2'))
console.log(format(' 12 '))
console.log(format('123 '))
console.log(format(' 123'))
console.log(format(' 1 2 3'))
console.log(format('1 2 3 '))
console.log(format('12 34'))
console.log(format('123   45678'))
console.log(format('12349  567  8'))
console.log(format('  1234 9567   81   '))
console.log(format('  1234 9567   81 9 7 5 6 4 5 8 '))
console.log(format('  1234 9567   81 c  '))
Rick
  • 1,035
  • 10
  • 18