Konvertieren Sie in JavaScript eine lange Zahl in eine abgekürzte Zeichenfolge mit einer besonderen Anforderung an die Kürze


79

Wie würde man in JavaScript eine Funktion schreiben, die eine bestimmte [edit: positive Ganzzahl ] -Zahl (unter 100 Milliarden) in eine 3-Buchstaben-Abkürzung umwandelt - wobei 0-9 und az / AZ als Buchstabe zählen, aber der Punkt (wie es in vielen proportionalen Schriftarten so klein ist) würde nicht und würde in Bezug auf die Buchstabenbegrenzung ignoriert werden?

Diese Frage bezieht sich auf diesen hilfreichen Thread , ist aber nicht dasselbe. Wenn diese Funktion beispielsweise "123456 -> 1,23 k" ("123,5 k" sind 5 Buchstaben) wird, suche ich nach etwas, das "123456 -> 0,1 m" ("0 [.] 1 m" bedeutet 3 Buchstaben) ). Dies wäre beispielsweise die Ausgabe der erhofften Funktion (linkes Original, rechter idealer Rückgabewert):

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"

Vielen Dank!

Update: Danke! Eine Antwort ist in und funktioniert gemäß den Anforderungen, wenn die folgenden Änderungen vorgenommen werden:

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

Obwohl nicht JS, habe ich dasselbe in C ++ getan, das Sie unter gist.github.com/1870641 anzeigen können - der Prozess wird der gleiche sein. Möglicherweise ist es jedoch besser, nach Standardlösungen zu suchen.
CSL

Baz, mein aktueller Start ist nur eine leicht neu formatierte Funktion aus dem verknüpften Thread mit den genannten Problemen. Bevor ich versuchte, diese Funktion aufzupeppen, hatte ich gehofft, dass jemand anderes vielleicht schon irgendwo eine intelligente Funktion geschrieben hat oder weiß, wie man das einfach macht. Csl, das ist großartig, vielen Dank! Würde diese Konvertierung auch den erwähnten "0.1m" -Stil ausführen?
Philipp Lenssen

Ich habe meine Antwort auf stackoverflow.com/a/10600491/711085
ninjagecko

9
was ist shortNum? Sie verwenden nie ist, und es ist nicht einmal deklariert ..
vsync

1
Es gibt auch eine Mischung zwischen .und ,, also 1001.5wird zu Millionen statt zu Tausenden.
vsync

Antworten:


60

Ich glaube, die Lösung von ninjagecko entspricht nicht ganz dem von Ihnen gewünschten Standard. Die folgende Funktion funktioniert:

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

Bei Werten über 99 Billionen wird kein Buchstabe hinzugefügt, der einfach durch Anhängen an das Array "Suffixe" behoben werden kann.

Edit von Philipp folgt: Mit den folgenden Änderungen passt es perfekt zu allen Anforderungen!

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

Vielen Dank! Ich habe einige Änderungen vorgenommen, damit es zu 100% den Anforderungen entspricht, und Ihre Antwort bearbeitet (ich hoffe, dass dies der richtige Weg ist, dies in StackOverflow zu tun, bitte ändern Sie es bei Bedarf). Hervorragend!
Philipp Lenssen

Nur aus Neugier: Welchen Fall / welche Anforderung habe ich verpasst?
Chucktator

1
Diese waren geringfügig und wurden aufgrund Ihrer großartigen Antwort schnell geändert. Die folgenden Testnummern wurden leicht verfehlt: 123 wurde zu 0,12k (ideales Ergebnis: 123, da dies immer noch 3 Buchstaben sind und somit in Ordnung); 123456 wurde 0,12 m (ideal: 0,1 m, da 0,12 m 4 Buchstaben minus Punkt sind); Gleiches gilt für 0,12b, das mit Änderungen nun zu 0,1b wird. Danke nochmal für deine Hilfe!
Philipp Lenssen

1
Ich habe gerade eine kleine Anpassung vorgenommen (noch nicht begutachtet). Ich habe Wert hinzugefügt = Math.round (Wert); bis zum Anfang der Funktion. Auf diese Weise wird es nicht unterbrochen, wenn "Wert" Dezimalstellen hat, z. 10025.26584 wird zu 10k anstelle von NaN
Daniel Tonon

2
shortNumist nicht definiert in der @ PhilippLenssen Bearbeitung am Endeif (shortValue % 1 != 0) shortNum = shortValue.toFixed(1);
Honza

43

Dies verarbeitet auch sehr große Werte und ist etwas prägnanter und effizienter.

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

Ergebnisse:

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

Ich mag diesen Ansatz, weil er Nicht-Ganzzahlen viel besser handhabt als die anderen Antworten.
Grant H.

Viel bessere Lösung
Danillo Corvalan

Vielen Dank. Ich habe das einfach in mein Projekt aufgenommen und es funktioniert wie ein Zauber. Tolle Lösung, sehr solide.
Spieglio

Für sehr kleine Werte (z. B. 5e-18) wird "0T" zurückgegeben, daher habe ich Folgendes hinzugefügt:if (num < 1e-3) { return '~0'; }
Paul Razvan Berg

16

Viele Antworten in diesem Thread werden durch die Verwendung von MathObjekten, Kartenobjekten, for-Schleifen usw. ziemlich kompliziert. Diese Ansätze verbessern das Design jedoch nicht wesentlich - sie führen zu mehr Codezeilen, mehr Komplexität und mehr Speicheraufwand . Nach der Bewertung mehrerer Ansätze ist der manuelle Ansatz meiner Meinung nach am einfachsten zu verstehen und bietet die höchste Leistung.

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


Dies sollte definitiv die akzeptierte Antwort sein. Bei weitem! Danke @tfmontague
Pedro Ferreira

14

Ich denke, Sie können diese Zahl nicht versuchen /

Wenn Sie 1000 in 1k konvertieren möchten

console.log(numeral(1000).format('0a'));

und wenn Sie 123400 in 123.4k konvertieren möchten, versuchen Sie dies

console.log(numeral(123400).format('0.0a'));

Fantastische Lösung, wenn Sie bereit sind, eine Bibliothek eines Drittanbieters zu installieren
Colby Cox

Gibt es eine Möglichkeit zu verwenden, 0.0aaber 1knicht anzuzeigen , 1.0kwenn die Zahl 1000 ist? (Trimmen der Nullen)
Paul Razvan Berg

14

Ich halte Folgendes für eine ziemlich elegante Lösung. Es wird nicht versucht, mit negativen Zahlen umzugehen :

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

Beispiele :

   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'

6
Dies löst die gestellte Frage nicht, aber es ist genau das, wonach ich suche. Vielen Dank.
Leff

Ich mag die SI-Symbole besser als k, m, b. 1b in Amerika / Großbritannien ist 1e9, aber 1e12 in vielen anderen Ländern.
Christiaan Westerbeek

8

Die moderne, einfach eingebaut, hochgradig anpassbar und 'no-Code' Art und Weise: Intl.FormatNumber ‚s - Format - Funktion ( Kompatibilität Graph )

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

Anmerkungen:


6

Basierend auf meiner Antwort unter https://stackoverflow.com/a/10600491/711085 ist Ihre Antwort tatsächlich etwas kürzer zu implementieren, indem Sie Folgendes verwenden .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;
    }
}

(Verwenden Sie wie üblich keine Mathematik, es sei denn, Sie wissen genau, was Sie tun. Das Zuweisen var pow=...und dergleichen würde zu wahnsinnigen Fehlern führen. Eine sicherere Methode finden Sie unter dem Link.)

> 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"

Sie müssen den Fall erfassen, in dem das Ergebnis> = 1 Billion ist. Wenn Ihre Anforderung für 3 Zeichen streng ist, besteht die Gefahr, dass beschädigte Daten erstellt werden, was sehr schlecht wäre.


Schöne Lösung. Auch verrückte Requisiten für die Verwendung der veralteten withAussage :)
stwilz

3

Code

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"

Prüfung:

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

Nachdem Sie alle oben in diesem Thread beschriebenen Lösungen ausprobiert haben, ist dies die einzige, die ordnungsgemäß funktioniert. Danke Danilo!
ty.

3

Hier ist eine andere Sichtweise. Ich wollte, dass 123456 123,4 K statt 0,1 M ist

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


1

Nach einigem Herumspielen scheint dieser Ansatz die erforderlichen Kriterien zu erfüllen. Lässt sich von der Antwort von @ chuckator inspirieren.

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

Ich finde diese Antwort großartig. Ich hatte einen etwas anderen Fall, in dem ich keine Werte mit führenden Nullen anzeigen wollte. Ich habe hinzugefügt, wenn (adjustedValue.charAt (0) === '0') {return adjustierterWert * 1000 + Suffixe [SuffixIndex - 1]; } else {return adjustierterWert + Suffixe [SuffixIndex]; }
user3162553

1

Ich benutze diese Funktion, um diese Werte zu erhalten.

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
}

Jede 3-stellige Stelle hat ein anderes Suffix, das versuche ich zuerst zu finden.

Entfernen Sie also das negative Symbol, falls vorhanden , und ermitteln Sie, wie viele 3 Ziffern in dieser Zahl enthalten sind.

Danach finden Sie das entsprechende Suffix basierend auf der vorherigen Berechnung, die zur geteilten Zahl hinzugefügt wurde.

Converter(1500, 1)

Wird zurückkehren:

1.5K

es ist etwas falsch. Der Konverter (824492, 1) gibt 0,8 M zurück. Es sollte 824k zurückkehren
Sebastian SALAMANCA

0

Intl ist das Javascript-Standardpaket für implementierte internationalisierte Verhaltensweisen. Intl.NumberFormatter ist speziell der lokalisierte Zahlenformatierer. Dieser Code berücksichtigt also tatsächlich Ihre lokal konfigurierten Tausender- und Dezimaltrennzeichen.

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) // Gibt 999B

Verwandte Frage: Kürzen Sie eine lokalisierte Zahl in JavaScript für Tausende (1k) und Millionen (1m) ab.


Aber dann sind die Suffixe nicht lokalisiert.
Glen-84

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

                }

alert (converse_number (100000000000));


0

@nimesaram

Ihre Lösung ist für den folgenden Fall nicht wünschenswert:

Input 50000
Output 50.0k

Die folgende Lösung funktioniert einwandfrei.

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

Ein Hinweis: Mit Ausnahme von k für Kilo sind alle Präfixe in Großbuchstaben. Vergleiche en.wikipedia.org/wiki/Unit_prefix
Wiimm

Oh Danke! Eigentlich braucht mein Anwendungsfall alles in Kleinbuchstaben.
Rishabh

0

Verwendung als Zahlenprototyp

Für einfache und direkte Sie. Machen Sie einfach einen Prototyp daraus. Hier ist ein Beispiel.

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

0

Indisches Währungsformat bis (K, L, C) Tausend, 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";
};
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.