【问题标题】:Align numbers in sublist对齐子列表中的数字
【发布时间】:2016-12-27 18:43:51
【问题描述】:

考虑到逗号,我有一组数字要对齐:

   10    3          
  200    4000,222  3  1,5 
  200,21          0,3  2   
30000    4,5      1      

mylist = [['10', '3', '', ''], 
          ['200', '4000,222', '3', '1,5'], 
          ['200,21', '', '0,3', '2'], 
          ['30000', '4,5', '1', '']]

我想要的是考虑逗号来对齐这个列表:

预期结果:

mylist = [['   10   ', '   3    ', '   ', '   '], 
          ['  200   ', '4000,222', '3  ', '1,5'], 
          ['  200,21', '        ', '0,3', '2  '], 
          ['30000   ', '   4,5  ', '1  ', '   ']]

我试着翻个单子:

mynewlist = list(zip(*mylist))  

并在每个子列表中查找逗号后最长的部分:

for m in mynewlist:
    max([x[::-1].find(',') for x in m]

并使用 rjust 和 ljust 但我不知道如何在逗号之后和 rjust 在逗号之前,两者都在同一个字符串中。

如何在不使用 format() 的情况下解决此问题? (我想与 ljust 和 rjust 对齐)

【问题讨论】:

  • @JimFasarakis-Hilliard,肯定 str.center 没问题。但是对齐中心没有如上的结果。
  • @JimFasarakis-Hilliard 你为什么要删除你的答案?看起来不错。我希望这只是暂时的。关于sum(,[]):我发现使用起来很有趣,但问题是它每次都使用a = a+b而不是a+=b

标签: python list python-3.x numbers alignment


【解决方案1】:

这是目前可以解决问题的另一种方法。不幸的是,我看不到任何简单的方法来完成这项工作,可能是由于时间的原因:-)

不管怎样,我会解释的。 r 是之前创建的结果列表。

r = [[] for i in range(4)]

然后我们遍历这些值并使用enumerate 获取索引:

for ind1, vals in enumerate(zip(*mylist)):

在循环中,我们获取存在的十进制数字的最大长度和单词的最大长度(没有十进制数字的单词):

    l = max(len(v.partition(',')[2]) for v in vals) + 1
    mw = max(len(v if ',' not in v else v.split(',')[0]) for v in vals)

现在我们检查元组 vals 中的值并构建我们的结果(是的,目前无法想到避免这种嵌套的方法)。

    for ind2, v in enumerate(vals):

如果它包含逗号,则应采用不同的格式。具体来说,我们 rjust 它基于单词的最大长度 mw 然后添加十进制数字和所需的任何空格:

        if ',' in v:
            n, d = v.split(',')
            v = "".join((n.rjust(mw),',', d, " " * (l - 1 - len(d))))

在相反的情况下,我们只需.rjust,然后添加空格:

        else:
            v = "".join((v.rjust(mw) + " " * l))

最后,我们 appendr

        r[ind1].append(v)

大家一起:

r = [[] for i in range(4)]
for ind1, vals in enumerate(zip(*mylist)):
    l = max(len(v.partition(',')[2]) for v in vals) + 1
    mw = max(len(v if ',' not in v else v.split(',')[0]) for v in vals)
    for ind2, v in enumerate(vals):
        if ',' in v:
            n, d = v.split(',')
            v = "".join((n.rjust(mw),',', d, " " * (l - 1 - len(d))))
        else:
            v = "".join((v.rjust(mw) + " " * l))
        r[ind1].append(v)

现在,我们可以打印出来了:

>>> print(*map(list,zip(*r)), sep='\n)
['   10   ', '   3    ', '   ', '   ']
['  200   ', '4000,222', '3  ', '1,5']
['  200,21', '        ', '0,3', '2  ']
['30000   ', '   4,5  ', '1  ', '   ']

【讨论】:

  • 很好,但是计算最大字符串长度的方法效率低下:sum 在列表上不是很好(最好使用itertools.chain),您不必为此创建新列表就做l = max(len(x) for l in mylist for x in l)
  • chain 确实是最好的。我在这里接受了你的第二个建议,不要导入东西。出于某种原因,我总是在这种情况下提出sum(..,[]),这很吸引我:-)
【解决方案2】:

这里有一个不同的解决方案,它不会转置my_list,而是对其进行两次迭代。在第一次通过时,它会生成一个元组列表,每列一个。每个元组是一对数字,其中第一个数字是逗号之前的长度,第二个数字是逗号的长度以及它后面的所有内容。例如'4000,222' 结果为(4, 4)。在第二遍时,它会根据第一遍生成的格式信息来格式化数据。

from functools import reduce

mylist = [['10', '3', '', ''],
          ['200', '4000,222', '3', '1,5'], 
          ['200,21', '', '0,3', '2'], 
          ['30000', '4,5', '1', '']]

# Return tuple (left part length, right part length) for given string
def part_lengths(s):
    left, sep, right = s.partition(',')
    return len(left), len(sep) + len(right)

# Return string formatted based on part lengths
def format(s, first, second):
    left, sep, right = s.partition(',')
    return left.rjust(first) + sep + right.ljust(second - len(sep))

# Generator yielding part lengths row by row
parts = ((part_lengths(c) for c in r) for r in mylist)

# Combine part lengths to find maximum for each column
# For example data it looks like this: [[5, 3], [4, 4], [1, 2], [1, 2]]
sizes = reduce(lambda x, y: [[max(z) for z in zip(a, b)] for a, b in zip(x, y)], parts)

# Format result based on part lengths
res = [[format(c, *p) for c, p in zip(r, sizes)] for r in mylist]

print(*res, sep='\n')

输出:

['   10   ', '   3    ', '   ', '   ']
['  200   ', '4000,222', '3  ', '1,5']
['  200,21', '        ', '0,3', '2  ']
['30000   ', '   4,5  ', '1  ', '   ']

【讨论】:

    【解决方案3】:

    这适用于 python 2 和 3。不过,我没有使用 ljust 或 rjust,我只是在数字前后添加了与列中最大大小数字一样多的空格:

    mylist = [['10', '3', '', ''], 
              ['200', '4000,222', '3', '1,5'], 
              ['200,21', '', '0,3', '2'], 
              ['30000', '4,5', '1', '']]
    transposed = list(zip(*mylist))
    sizes = [[(x.index(",") if "," in x else len(x), len(x) - x.index(",") if "," in x else 0)
      for x in l] for l in transposed]
    maxima = [(max([x[0] for x in l]), max([x[1] for x in l])) for l in sizes]
    withspaces = [
      [' ' * (maxima[i][0] - sizes[i][j][0]) + number + ' ' * (maxima[i][1] - sizes[i][j][1])
      for j, number in enumerate(l)] for i, l in enumerate(transposed)]
    result = list(zip(*withspaces))
    

    在python3中打印结果:

    >>> print(*result, sep='\n')                             
    ('   10   ', '   3    ', '   ', '   ')
    ('  200   ', '4000,222', '3  ', '1,5')
    ('  200,21', '        ', '0,3', '2  ')
    ('30000   ', '   4,5  ', '1  ', '   ')
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-12-13
      • 2012-06-17
      • 2013-07-12
      • 2021-07-29
      • 2018-06-02
      • 2016-06-15
      • 2013-06-04
      相关资源
      最近更新 更多