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('');
8
  • 6
    No need for a library or a home-grown solution. Every current browser supports Number.prototype.toLocaleString. Commented Jan 7, 2019 at 15:19
  • If you want to roll your own concisely, at the expense of readability for some ... stackoverflow.com/a/2901298/294949 Commented Jan 7, 2019 at 15:20
  • 2
    Number("12345").toLocaleString(); Commented Jan 7, 2019 at 15:21
  • 1
    input.toLocaleString('en-US'). Specify the en-US for a 1000's separator. Number representation in en-IN, for example, is different Commented Jan 7, 2019 at 15:27
  • 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("") Commented Jan 7, 2019 at 16:22

6 Answers 6

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;}

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

Comments

2

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()

Comments

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', ','));

Comments

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);

Comments

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, ','));

Comments

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  '))

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.