En JavaScript, ¿cómo se escribiría una función que convierta un número dado [editar: entero positivo ] (por debajo de 100 mil millones) en una abreviatura de 3 letras, donde 0-9 y az / AZ cuentan como una letra, pero el punto (ya que es tan pequeño en muchas fuentes proporcionales) no lo haría, y sería ignorado en términos del límite de letras?
Esta pregunta está relacionada con este útil hilo , pero no es lo mismo; por ejemplo, dónde se convertiría esa función, por ejemplo, "123456 -> 1.23k" ("123.5k" son 5 letras). Estoy buscando algo que haga "123456 -> 0.1m" ("0 [.] 1m" sea de 3 letras ). Por ejemplo, este sería el resultado de la función esperada (original izquierdo, valor de retorno ideal derecho):
0 "0"
12 "12"
123 "123"
1234 "1.2k"
12345 "12k"
123456 "0.1m"
1234567 "1.2m"
12345678 "12m"
123456789 "0.1b"
1234567899 "1.2b"
12345678999 "12b"
¡Gracias!
Actualización: ¡Gracias! Hay una respuesta y funciona según los requisitos cuando se realizan las siguientes enmiendas:
function abbreviateNumber(value) {
var newValue = value;
if (value >= 1000) {
var suffixes = ["", "k", "m", "b","t"];
var suffixNum = Math.floor( (""+value).length/3 );
var shortValue = '';
for (var precision = 2; precision >= 1; precision--) {
shortValue = parseFloat( (suffixNum != 0 ? (value / Math.pow(1000,suffixNum) ) : value).toPrecision(precision));
var dotLessShortValue = (shortValue + '').replace(/[^a-zA-Z 0-9]+/g,'');
if (dotLessShortValue.length <= 2) { break; }
}
if (shortValue % 1 != 0) shortValue = shortValue.toFixed(1);
newValue = shortValue+suffixes[suffixNum];
}
return newValue;
}
fuente
shortNum
? nunca lo usa, y ni siquiera se declara ...
y,
, por lo que1001.5
se convierte en millones en lugar de miles.Respuestas:
Creo que la solución de ninjagecko no se ajusta del todo al estándar que querías. La siguiente función hace:
function intToString (value) { var suffixes = ["", "k", "m", "b","t"]; var suffixNum = Math.floor((""+value).length/3); var shortValue = parseFloat((suffixNum != 0 ? (value / Math.pow(1000,suffixNum)) : value).toPrecision(2)); if (shortValue % 1 != 0) { shortValue = shortValue.toFixed(1); } return shortValue+suffixes[suffixNum]; }
Para valores superiores a 99 billones no se agregará ninguna letra, que se puede arreglar fácilmente agregando a la matriz de 'sufijos'.
La edición de Philipp sigue: ¡ Con los siguientes cambios, se adapta perfectamente a todos los requisitos!
function abbreviateNumber(value) { var newValue = value; if (value >= 1000) { var suffixes = ["", "k", "m", "b","t"]; var suffixNum = Math.floor( (""+value).length/3 ); var shortValue = ''; for (var precision = 2; precision >= 1; precision--) { shortValue = parseFloat( (suffixNum != 0 ? (value / Math.pow(1000,suffixNum) ) : value).toPrecision(precision)); var dotLessShortValue = (shortValue + '').replace(/[^a-zA-Z 0-9]+/g,''); if (dotLessShortValue.length <= 2) { break; } } if (shortValue % 1 != 0) shortValue = shortValue.toFixed(1); newValue = shortValue+suffixes[suffixNum]; } return newValue; }
fuente
shortNum
no está definido en la edición de @ PhilippLenssen al finalif (shortValue % 1 != 0) shortNum = shortValue.toFixed(1);
Esto también maneja valores muy grandes y es un poco más conciso y eficiente.
abbreviate_number = function(num, fixed) { if (num === null) { return null; } // terminate early if (num === 0) { return '0'; } // terminate early fixed = (!fixed || fixed < 0) ? 0 : fixed; // number of decimal places to show var b = (num).toPrecision(2).split("e"), // get power k = b.length === 1 ? 0 : Math.floor(Math.min(b[1].slice(1), 14) / 3), // floor at decimals, ceiling at trillions c = k < 1 ? num.toFixed(0 + fixed) : (num / Math.pow(10, k * 3) ).toFixed(1 + fixed), // divide by power d = c < 0 ? c : Math.abs(c), // enforce -0 is 0 e = d + ['', 'K', 'M', 'B', 'T'][k]; // append power return e; }
Resultados:
for(var a='', i=0; i < 14; i++){ a += i; console.log(a, abbreviate_number(parseInt(a),0)); console.log(-a, abbreviate_number(parseInt(-a),0)); } 0 0 -0 0 01 1 -1 -1 012 12 -12 -12 0123 123 -123 -123 01234 1.2K -1234 -1.2K 012345 12.3K -12345 -12.3K 0123456 123.5K -123456 -123.5K 01234567 1.2M -1234567 -1.2M 012345678 12.3M -12345678 -12.3M 0123456789 123.5M -123456789 -123.5M 012345678910 12.3B -12345678910 -12.3B 01234567891011 1.2T -1234567891011 -1.2T 0123456789101112 123.5T -123456789101112 -123.5T 012345678910111213 12345.7T -12345678910111212 -12345.7T
fuente
5e-18
. Ej. ), Devuelve "0T", por lo que agregué esto:if (num < 1e-3) { return '~0'; }
Muchas respuestas en este hilo se vuelven bastante complicadas, usando
Math
objetos, objetos de mapa, bucles for, etc. Pero esos enfoques en realidad no mejoran mucho el diseño: introducen más líneas de código, más complejidad y más memoria. . Después de evaluar varios enfoques, creo que el enfoque manual es el más fácil de entender y proporciona el mayor rendimiento.const formatCash = n => { if (n < 1e3) return n; if (n >= 1e3 && n < 1e6) return +(n / 1e3).toFixed(1) + "K"; if (n >= 1e6 && n < 1e9) return +(n / 1e6).toFixed(1) + "M"; if (n >= 1e9 && n < 1e12) return +(n / 1e9).toFixed(1) + "B"; if (n >= 1e12) return +(n / 1e12).toFixed(1) + "T"; }; console.log(formatCash(1235000));
fuente
Esto es lo que creo que es una solución bastante elegante. No intenta lidiar con números negativos :
const COUNT_ABBRS = [ '', 'K', 'M', 'G', 'T', 'P', 'E', 'Z', 'Y' ]; function formatCount(count, withAbbr = false, decimals = 2) { const i = 0 === count ? count : Math.floor(Math.log(count) / Math.log(1000)); let result = parseFloat((count / Math.pow(1000, i)).toFixed(decimals)); if(withAbbr) { result += `${COUNT_ABBRS[i]}`; } return result; }
Ejemplos :
formatCount(1000, true); => '1k' formatCount(100, true); => '100' formatCount(10000, true); => '10k' formatCount(10241, true); => '10.24k' formatCount(10241, true, 0); => '10k' formatCount(10241, true, 1) => '10.2k' formatCount(1024111, true, 1) => '1M' formatCount(1024111, true, 2) => '1.02M'
fuente
Creo que no puedes probar este numeraljs /
Si quieres convertir 1000 a 1k
console.log(numeral(1000).format('0a'));
y si quieres convertir 123400 a 123.4k prueba esto
console.log(numeral(123400).format('0.0a'));
fuente
0.0a
pero1k
no mostrar1.0k
cuando el número es 1000? (Recortando los ceros)El 'sin código' forma moderna, fácil, incorporado, altamente personalizable, y: Intl.FormatNumber 's formato de la función ( gráfico de compatibilidad )
var numbers = [98721, 9812730,37462,29,093484620123, 9732,0283737718234712] for(let num of numbers){ console.log(new Intl.NumberFormat( 'en-US', { maximumFractionDigits: 1,notation: "compact" , compactDisplay: "short" }).format(num)); } 98.7K 9.8M 37.5K 29 93.5B 9.7K 283.7T
Notas:
//@ts-ignore
antesnotation
( fuente )options
parámetro: https://docs.w3cub.com/javascript/global_objects/numberformat/style: 'currency'
, debe eliminar maximumFractionDigits, ya que lo resolverá por usted.fuente
Según mi respuesta en https://stackoverflow.com/a/10600491/711085 , su respuesta es en realidad un poco más corta de implementar, utilizando
.substring(0,3)
:function format(n) { with (Math) { var base = floor(log(abs(n))/log(1000)); var suffix = 'kmb'[base-1]; return suffix ? String(n/pow(1000,base)).substring(0,3)+suffix : ''+n; } }
(Como de costumbre, no use Math a menos que sepa exactamente lo que está haciendo; asignar
var pow=...
y similares causaría errores locos. Vea el enlace para una forma más segura de hacer esto).> tests = [-1001, -1, 0, 1, 2.5, 999, 1234, 1234.5, 1000001, Math.pow(10,9), Math.pow(10,12)] > tests.forEach(function(x){ console.log(x,format(x)) }) -1001 "-1.k" -1 "-1" 0 "0" 1 "1" 2.5 "2.5" 999 "999" 1234 "1.2k" 1234.5 "1.2k" 1000001 "1.0m" 1000000000 "1b" 1000000000000 "1000000000000"
Deberá detectar el caso en el que el resultado es> = 1 billón, si su requisito de 3 caracteres es estricto, de lo contrario, corre el riesgo de crear datos corruptos, lo que sería muy malo.
fuente
with
declaración obsoleta :)Código
const SI_PREFIXES = [ { value: 1, symbol: '' }, { value: 1e3, symbol: 'k' }, { value: 1e6, symbol: 'M' }, { value: 1e9, symbol: 'G' }, { value: 1e12, symbol: 'T' }, { value: 1e15, symbol: 'P' }, { value: 1e18, symbol: 'E' }, ] const abbreviateNumber = (number) => { if (number === 0) return number const tier = SI_PREFIXES.filter((n) => number >= n.value).pop() const numberFixed = (number / tier.value).toFixed(1) return `${numberFixed}${tier.symbol}` } abbreviateNumber(2000) // "2.0k" abbreviateNumber(2500) // "2.5k" abbreviateNumber(255555555) // "255.6M"
Prueba:
import abbreviateNumber from './abbreviate-number' test('abbreviateNumber', () => { expect(abbreviateNumber(0)).toBe('0') expect(abbreviateNumber(100)).toBe('100') expect(abbreviateNumber(999)).toBe('999') expect(abbreviateNumber(1000)).toBe('1.0k') expect(abbreviateNumber(100000)).toBe('100.0k') expect(abbreviateNumber(1000000)).toBe('1.0M') expect(abbreviateNumber(1e6)).toBe('1.0M') expect(abbreviateNumber(1e10)).toBe('10.0G') expect(abbreviateNumber(1e13)).toBe('10.0T') expect(abbreviateNumber(1e16)).toBe('10.0P') expect(abbreviateNumber(1e19)).toBe('10.0E') expect(abbreviateNumber(1500)).toBe('1.5k') expect(abbreviateNumber(1555)).toBe('1.6k') expect(abbreviateNumber(undefined)).toBe('0') expect(abbreviateNumber(null)).toBe(null) expect(abbreviateNumber('100')).toBe('100') expect(abbreviateNumber('1000')).toBe('1.0k') })
fuente
Aquí hay otra versión. Quería que 123456 fuera 123.4K en lugar de 0.1M
function convert(value) { var length = (value + '').length, index = Math.ceil((length - 3) / 3), suffix = ['K', 'M', 'G', 'T']; if (length < 4) return value; return (value / Math.pow(1000, index)) .toFixed(1) .replace(/\.0$/, '') + suffix[index - 1]; } var tests = [1234, 7890, 123456, 567890, 800001, 2000000, 20000000, 201234567, 801234567, 1201234567]; for (var i in tests) document.writeln('<p>convert(' + tests[i] + ') = ' + convert(tests[i]) + '</p>');
fuente
Después de jugar un poco, este enfoque parece cumplir con los criterios requeridos. Se inspira en la respuesta de @ chuckator.
function abbreviateNumber(value) { if (value <= 1000) { return value.toString(); } const numDigits = (""+value).length; const suffixIndex = Math.floor(numDigits / 3); const normalisedValue = value / Math.pow(1000, suffixIndex); let precision = 2; if (normalisedValue < 1) { precision = 1; } const suffixes = ["", "k", "m", "b","t"]; return normalisedValue.toPrecision(precision) + suffixes[suffixIndex]; }
fuente
Estoy usando esta función para obtener estos valores.
function Converter(number, fraction) { let ranges = [ { divider: 1, suffix: '' }, { divider: 1e3, suffix: 'K' }, { divider: 1e6, suffix: 'M' }, { divider: 1e9, suffix: 'G' }, { divider: 1e12, suffix: 'T' }, { divider: 1e15, suffix: 'P' }, { divider: 1e18, suffix: 'E' }, ] //find index based on number of zeros let index = (Math.abs(number).toString().length / 3).toFixed(0) return (number / ranges[index].divider).toFixed(fraction) + ranges[index].suffix }
Cada 3 dígitos tiene un sufijo diferente, eso es lo que estoy tratando de encontrar en primer lugar.
Entonces, elimine el símbolo negativo si existe , luego encuentre cuántos 3 dígitos hay en este número.
después de eso, busque el sufijo apropiado basado en el cálculo anterior agregado al número dividido.
Converter(1500, 1)
Regresará:
1.5K
fuente
Intl es el 'paquete' estándar de Javascript para los comportamientos internacionalizados implementados. Intl.NumberFormatter es específicamente el formateador de números localizado. Entonces, este código realmente respeta los miles y separadores decimales configurados localmente.
intlFormat(num) { return new Intl.NumberFormat().format(Math.round(num*10)/10); } abbreviateNumber(value) { let num = Math.floor(value); if(num >= 1000000000) return this.intlFormat(num/1000000000)+'B'; if(num >= 1000000) return this.intlFormat(num/1000000)+'M'; if(num >= 1000) return this.intlFormat(num/1000)+'k'; return this.intlFormat(num); }
abbreviateNumber (999999999999) // Da 999B
Pregunta relacionada: abreviar un número localizado en JavaScript para miles (1k) y millones (1m)
fuente
function converse_number (labelValue) { // Nine Zeroes for Billions return Math.abs(Number(labelValue)) >= 1.0e+9 ? Math.abs(Number(labelValue)) / 1.0e+9 + "B" // Six Zeroes for Millions : Math.abs(Number(labelValue)) >= 1.0e+6 ? Math.abs(Number(labelValue)) / 1.0e+6 + "M" // Three Zeroes for Thousands : Math.abs(Number(labelValue)) >= 1.0e+3 ? Math.abs(Number(labelValue)) / 1.0e+3 + "K" : Math.abs(Number(labelValue)); }
alerta (número_conversación (100000000000));
fuente
@nimesaram
Su solución no será deseable para el siguiente caso:
Input 50000 Output 50.0k
La siguiente solución funcionará bien.
const convertNumberToShortString = ( number: number, fraction: number ) => { let newValue: string = number.toString(); if (number >= 1000) { const ranges = [ { divider: 1, suffix: '' }, { divider: 1e3, suffix: 'k' }, { divider: 1e6, suffix: 'm' }, { divider: 1e9, suffix: 'b' }, { divider: 1e12, suffix: 't' }, { divider: 1e15, suffix: 'p' }, { divider: 1e18, suffix: 'e' } ]; //find index based on number of zeros const index = Math.floor(Math.abs(number).toString().length / 3); let numString = (number / ranges[index].divider).toFixed(fraction); numString = parseInt(numString.substring(numString.indexOf('.') + 1)) === 0 ? Math.floor(number / ranges[index].divider).toString() : numString; newValue = numString + ranges[index].suffix; } return newValue; }; // Input 50000 // Output 50k // Input 4500 // Output 4.5k
fuente
Usar como prototipo numérico
Para fácil y directo. Simplemente haz un prototipo. Aquí hay un ejemplo.
Number.prototype.abbr = function (decimal = 2): string { const notations = ['', 'k', 'M', 'G', 'T', 'P', 'E', 'Z', 'Y'], i = Math.floor(Math.log(this) / Math.log(1000)); return `${parseFloat((this / Math.pow(1000, i)).toFixed(decimal))}${notations[i]}`; };
fuente
Formato de moneda india a (K, L, C) mil, lakh, crore
const formatCash = n => { if (n < 1e3) return n; if (n >= 1e3 && n < 1e5) return +(n / 1e3).toFixed(1) + "K"; if (n >= 1e5 && n <= 1e6) return +(n / 1e5).toFixed(1) + "L"; if (n >= 1e6 && n <= 1e9) return +(n / 1e7).toFixed(1) + "C"; };
fuente