Сокращение больших чисел с плавающей запятой до формата 12.342M или 1.023B в python
Пытаюсь написать функцию, что получает на вход длинное или не очень число и возвращает это же число, но сокращенное до формата, что указан в заголовке вопроса.
К примеру функция получает число 2 454 232, а возвращает его же, но в формате 2.454m. Или 123 456 789 012 будет приведено к 123.456b.
Т.е. выводятся перые знаки числа(будь то 1, 10, 100 миллионов), затем ставится точка или запятая и после выводятся 3 последующие знака, будь то 001, 011, 111 или вообще 000(хотя возможно в ситуации с 000 можно было бы просто выводить первое число без точки, но это не так критично).
У меня получилось сокращение числа до самых первых первых знаков, чтобы выводилось к примеру 2m или 133b, но реализовать тысячные или миллионные после запятой у меня не выходит.
Знает ли кто то как можно дополнить функцию, чтобы она корректно работала и возвращала числа после запятой?
Заранее спасибо за ответ.
'''
def shorten_number(number_to_shorten):
str_number_to_shorten = str(number_to_shorten)
if len(str_number_to_shorten) > 9 and len(str_number_to_shorten) <= 12:
return str_number_to_shorten[:-9] + "B"
elif len(str_number_to_shorten) >= 7 and len(str_number_to_shorten) <= 9:
return str_number_to_shorten[:-6] + "M"
else:
return number_to_shorten
'''
Ответы (2 шт):
Могу предложить такой вариант, но есть изъян.
def shorten_number(number_to_shorten):
postfixes = ['m', 'b', ] # постфиксы для сокращенных чисел
briefer_nums = [10**k for k in range(6, 6+3*len(postfixes), 3)] # список наших делителей
for i in reversed(range(len(postfixes))):
if number_to_shorten >= briefer_nums[i]:
num = number_to_shorten/briefer_nums[i]
return f'{num:.3f}{postfixes[i]}'
Собственно, изъян следующий: при попытке сократить число 123 456 789 012 получаем не 123.456b, а 123.457b из-за того, как работает округление.
Избавился от "изъяна"
def shorten_number(number_to_shorten):
postfixes = ['m', 'b', ] # постфиксы для сокращенных чисел
briefer_nums = [10**k for k in range(6, 6+3*len(postfixes), 3)] # список наших делителей
for i in reversed(range(len(postfixes))):
if number_to_shorten >= briefer_nums[i]:
num = number_to_shorten / briefer_nums[i]
int_part = int(num)
float_part = str(num - int_part).split('.')[1][:3]
return str(int_part) + '.' + float_part + postfixes[i]
Небольшая оптимизация расхода памяти и выделения целой и дробной частей:
def shorten_number(number_to_shorten):
postfixes = ['m', 'b', ] # постфиксы для сокращенных чисел
briefer_num = (10**(len(postfixes)+1))**3
for i in reversed(range(len(postfixes))):
if number_to_shorten >= briefer_num:
num = number_to_shorten / briefer_num
int_part, float_part = str(num).split('.')
return int_part + '.' + float_part[:3] + postfixes[i]
briefer_num //= 1000
def format_large_number(num: int | float):
suffixes = ['K', 'M', 'B']
if num < 1000:
return str(num)
num = float(num)
for suffix in suffixes:
num /= 1000
if abs(num) < 1000:
return '{:.1f}{}'.format(num, suffix)
return '{:.1f}{}'.format(num, 'T')
столкнулся с похожей задачей и накидал такое решение