Python 基于整数和小数部分的位数的十进制格式

Python 基于整数和小数部分的位数的十进制格式,python,python-3.x,string-formatting,Python,Python 3.x,String Formatting,根据整数和小数部分的位数设置小数格式的最简单方法是什么?假设用户选择查看4位数字,那么我有这个测试用例: [('11111.1', '11111'), # Integer part has >= 4 digits keep only integer part ('111.11', '111.1'), # Integer part has < 4 digits keep total 4 digits ('11.111', '11.11'), ('1.1111

根据整数和小数部分的位数设置小数格式的最简单方法是什么?假设用户选择查看4位数字,那么我有这个测试用例:

[('11111.1', '11111'),    # Integer part has >= 4 digits keep only integer part
 ('111.11', '111.1'),     # Integer part has < 4 digits keep total 4 digits
 ('11.111', '11.11'),    
 ('1.1111', '1.111'),
 ('0.00111', '0.0011'),   # Integer part has no digits keep 4 decimal part digits
 ('0.000011', '0.00001')] # First not zero digit place is > 4 keep first digit

看不到简单的一行两行解决方案。下面的代码解决了您的问题

def formatNumber(a, DIGITS_TO_KEEP):
    p = a.index('.')
    if p >= DIGITS_TO_KEEP:
        return a[:p]
    else:
        q = 0
        while q+1 < len(a) and (a[q]=='.' or a[q]=='0'):
            q += 1
        return a[:max(DIGITS_TO_KEEP, q)+1]

for case in ['11111.1', '111.11', '11.111', '1.1111', '0.00111', '0.000011']:
    print case, ":", formatNumber(case, 4)
def formatNumber(a,保留数字):
p=a.指数('.'))
如果p>=要保留的数字:
返回a[:p]
其他:
q=0
当q+1
在不同的列表中排序之前,需要先获得十进制级别

import math

def get_decimal_level(number):
    return int(round(math.log(number, 10), 10)) + 1
测试一下

>>> get_decimal_level(99999)
5
>>> get_decimal_level(100000)
6
让它工作

from collections import defaultdict

def group_list_on_levels(numbers):
    group_numbers = defaultdict(list)

    for number in numbers:
        group_numbers[get_decimal_level(number)].append(number)

    levels = group_numbers.keys()
    levels.sort(reverse=True)

    return [group_numbers[key] for level in levels]

numbers = [31243,543543.654,543543,0.001]
final_list = group_list_on_levels(numbers)
print(final_list) # Check your answer
在控制台中,我得到

[[543543.654, 543543], [31243], [0.001]]

p.S.和无十进制字符串转换

您只需使用嵌套格式参数调用
str.format
即可完成所有操作:

def format_float(value, ndigits=4):
    j = min(i-1 for i in range(ndigits+1) if value >= 10 ** (ndigits - i))
    return '{:.0{num_digits}f}'.format(value, num_digits=max(0,j))
其思想是小数位数应等于最小值
i
,以便该值大于
10^(ndigits-i)
。如果指定
0
的小数位数,则该数字将四舍五入为整数,因此输出正确

示例用法:

In [66]: inputs = [11111.1, 111.11, 11.111, 1.1111]

In [67]: for inp in inputs:
    ...:     print('Input = {} -- output = {}'.format(inp, format_float(inp, 4)))
Input = 11111.1 -- output = 11111
Input = 111.11 -- output = 111.1
Input = 11.111 -- output = 11.11
Input = 1.1111 -- output = 1.111
但是,如果输入很小,则会失败:

In [68]: format_float(0.0001, 4)
---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
<ipython-input-68-68e3461a51e5> in <module>()
----> 1 format_float(0.0001, 4)

<ipython-input-64-d4485ac4e1c9> in format_float(value, ndigits)
      1 def format_float(value, ndigits=4):
----> 2     j = min(i-1 for i in range(ndigits+1) if value >= 10 ** (ndigits - i))
      3     return '{:.0{num_digits}f}'.format(value, num_digits=max(0,j))

ValueError: min() arg is an empty sequence
这似乎适用于问题中提供的输入:

In [81]: inputs = [11111.1, 111.11, 11.111, 1.1111, 0.00111, 0.000011]

In [82]: for inp in inputs:
    ...:     print('Input = {} -- output = {}'.format(inp, format_float(inp, 4)))
Input = 11111.1 -- output = 11111
Input = 111.11 -- output = 111.1
Input = 11.111 -- output = 11.11
Input = 1.1111 -- output = 1.111
Input = 0.00111 -- output = 0.0011
Input = 1.1e-05 -- output = 0.00001
这不处理负数,但很容易检查负数并使用绝对值:

def format_float(value, ndigits):
    sign = ''
    if value < 0:
        value = abs(value)
        sign = '-'

    if value >= 1:
        j = min(i-1 for i in range(ndigits+1) if value >= 10 ** (ndigits - i))
        return '{}{:.0{num_digits}f}'.format(sign, value, num_digits=max(0,j))
    s = '{:.17f}'.format(value).rstrip('0')
    _, dec_part = s.split('.')
    if not dec_part:
        # Happens only with 0.0
        return '0'
    if len(dec_part) < ndigits or set(dec_part[:ndigits]) != {'0'}:
        # truncate the decimal representation
        dec_part = dec_part.ljust(ndigits, '0')[:ndigits]
    elif len(dec_part) > ndigits:
        # too small. Just find the first decimal place
        for i, char in enumerate(dec_part):
            if char != '0':
                dec_part = dec_part[:i+1]
                break
    return '{}{}.{}'.format(sign, 0, dec_part)
def格式\u浮点(值,ndigit):
符号=“”
如果值<0:
值=绝对值(值)
符号='-'
如果值>=1:
j=min(如果值>=10**(ndigits-i),则范围内的i为i-1(ndigits+1))
返回“{}{:.0{num_digits}f}”。格式(符号,值,num_digits=max(0,j))
s='{.17f}'。格式(值).rstrip('0')
_,dec_part=s.split('.'))
如果不是dec_零件:
#仅在0.0时发生
返回“0”
如果len(dec_部分)NDIGTS:
#太小了。只要找到第一个小数位
对于i,枚举中的字符(dec_部分):
如果char!='0':
dec_part=dec_part[:i+1]
打破
返回“{}{}.{}”。格式(符号,0,dec_部分)

您已经尝试了什么?你能展示一些你已经玩过的代码吗?我假设你的第五个值是
0.0011
,对吗?@TimPietzcker谢谢,修复了我的错误。注意:在python3中,如果你调用
round
而没有参数,它将返回一个整数。因此,执行
int(round(x,0))
是编写
round(x)
更复杂的方法。您希望
1111111
是什么?
In [81]: inputs = [11111.1, 111.11, 11.111, 1.1111, 0.00111, 0.000011]

In [82]: for inp in inputs:
    ...:     print('Input = {} -- output = {}'.format(inp, format_float(inp, 4)))
Input = 11111.1 -- output = 11111
Input = 111.11 -- output = 111.1
Input = 11.111 -- output = 11.11
Input = 1.1111 -- output = 1.111
Input = 0.00111 -- output = 0.0011
Input = 1.1e-05 -- output = 0.00001
def format_float(value, ndigits):
    sign = ''
    if value < 0:
        value = abs(value)
        sign = '-'

    if value >= 1:
        j = min(i-1 for i in range(ndigits+1) if value >= 10 ** (ndigits - i))
        return '{}{:.0{num_digits}f}'.format(sign, value, num_digits=max(0,j))
    s = '{:.17f}'.format(value).rstrip('0')
    _, dec_part = s.split('.')
    if not dec_part:
        # Happens only with 0.0
        return '0'
    if len(dec_part) < ndigits or set(dec_part[:ndigits]) != {'0'}:
        # truncate the decimal representation
        dec_part = dec_part.ljust(ndigits, '0')[:ndigits]
    elif len(dec_part) > ndigits:
        # too small. Just find the first decimal place
        for i, char in enumerate(dec_part):
            if char != '0':
                dec_part = dec_part[:i+1]
                break
    return '{}{}.{}'.format(sign, 0, dec_part)