Ce que vous êtes sur le point de trouver ci-dessous n'est en aucun cas la solution la plus performante ou la plus courte parmi celles déjà publiées. Au lieu de cela, il se concentre sur un problème particulier que la plupart des autres réponses manquent.
A savoir le cas où une entrée comme 999_995
est donnée:
Python 3.6.1 ...
...
>>> value = 999_995
>>> base = 1000
>>> math.log(value, base)
1.999999276174054
qui, étant tronqué à l'entier le plus proche et appliqué de nouveau à l'entrée, donne
>>> order = int(math.log(value, base))
>>> value/base**order
999.995
Cela semble être exactement ce à quoi nous nous attendions jusqu'à ce que nous soyons tenus de contrôler la précision de la sortie . Et c'est là que les choses commencent à devenir un peu difficiles.
Avec une précision de 2 chiffres, nous obtenons:
>>> round(value/base**order, 2)
1000 # K
au lieu de 1M
.
Comment pouvons-nous contrer cela?
Bien sûr, nous pouvons le vérifier explicitement:
if round(value/base**order, 2) == base:
order += 1
Mais pouvons-nous faire mieux? Pouvons-nous savoir de quelle façon les order
coupes devraient être effectuées avant de faire la dernière étape?
Il s'avère que nous le pouvons.
En supposant une règle d'arrondi de 0,5 décimal, la if
condition ci-dessus se traduit par:
résultant en
def abbreviate(value, base=1000, precision=2, suffixes=None):
if suffixes is None:
suffixes = ['', 'K', 'M', 'B', 'T']
if value == 0:
return f'{0}{suffixes[0]}'
order_max = len(suffixes) - 1
order = log(abs(value), base)
order_corr = order - int(order) >= log(base - 0.5/10**precision, base)
order = min(int(order) + order_corr, order_max)
factored = round(value/base**order, precision)
return f'{factored:,g}{suffixes[order]}'
donnant
>>> abbreviate(999_994)
'999.99K'
>>> abbreviate(999_995)
'1M'
>>> abbreviate(999_995, precision=3)
'999.995K'
>>> abbreviate(2042, base=1024)
'1.99K'
>>> abbreviate(2043, base=1024)
'2K'