【问题标题】:How to print a list more nicely?如何更好地打印列表?
【发布时间】:2010-12-04 04:37:30
【问题描述】:

这类似于How to print a list in Python “nicely”,但我希望将列表打印得更好——不带括号、撇号和逗号,在列中甚至更好。

foolist = ['exiv2-devel', 'mingw-libs', 'tcltk-demos', 'fcgi', 'netcdf', 
    'pdcurses-devel',     'msvcrt', 'gdal-grass', 'iconv', 'qgis-devel', 
    'qgis1.1', 'php_mapscript']

evenNicerPrint(foolist)

想要的结果:

exiv2-devel       msvcrt        
mingw-libs        gdal-grass    
tcltk-demos       iconv         
fcgi              qgis-devel    
netcdf            qgis1.1       
pdcurses-devel    php_mapscript 

谢谢!

【问题讨论】:

  • 首先,将dict用作变量名不是一个好主意其次,您要在此处打印的内容是一个列表,dict使用{}和:来分隔键和值
  • -1:问题的标题是“列表”——完全重复。问题是“dict”。示例代码是一个列表——完全重复。您是否希望将列表转换为字典并打印?如果是这样,请修正问题以描述您真正想要什么。
  • 我已按照建议更正了描述和示例代码。标题和描述现在反映了我的目标。感谢您的更正。
  • 如果投反对票是因为最初的混乱和措辞不佳,请收回他们,因为这已得到修复。如果否决票是出于其他原因,请解释我可能会解决这个问题,或者至少不会再犯同样的错误。谢谢。
  • 在 2021 年,我强烈建议查看来自 ClaudioEpic Wink 的答案,因为他们使用了 columnize

标签: python printing


【解决方案1】:

虽然不是为此而设计的,但 Python 3 cmd 中的标准库模块有一个实用程序,用于在多列中打印字符串列表

import cmd
cli = cmd.Cmd()
cli.columnize(foolist, displaywidth=80)

您甚至可以选择指定输出位置,cmd.Cmd(stdout=my_stream)

【讨论】:

  • 对于 python 3 来说,这是最简洁直接的方法。
【解决方案2】:

对于Python3,我使用python - How do you split a list into evenly sized chunks? - Stack Overflow创建

def chunkSectionList(listToPrint, columns):
    """ separate a list into chunks of n-items """
    for i in range(0, len(listToPrint), columns):
        yield listToPrint[i:i + columns]


def printSections(listToPrint, columns):
    remainder = len(listToPrint) % columns
    listToPrint += (columns - remainder) * \
        (" ") if remainder != 0 else listToPrint
    for sectionsLine in chunkSectionList(listToPrint, columns):
        formatStr = columns * '{:<30}'
        print(formatStr.format(* sectionsLine))

【讨论】:

    【解决方案3】:

    我使用 IPython 内部 columnize function

    import IPython
    foolist = ['exiv2-devel', 'mingw-libs', 'tcltk-demos', 'fcgi', 'netcdf', 
               'pdcurses-devel', 'msvcrt', 'gdal-grass', 'iconv', 'qgis-devel', 
               'qgis1.1', 'php_mapscript']
    
    foolist_columnized = IPython.utils.text.columnize(foolist)
    print(foolist_columnized)
    
    

    输出将如下所示:

    exiv2-devel  tcltk-demos  netcdf          msvcrt      iconv       qgis1.1
    mingw-libs   fcgi         pdcurses-devel  gdal-grass  qgis-devel  php_mapscript
    

    【讨论】:

      【解决方案4】:

      这里是简单的方法

      def printList1(list, col, STR_FMT='{}', gap=1):
          list = [STR_FMT.format(x).lstrip() for x in list]
          FMT2 = '%%%ds%%s' % (max(len(x) for x in list)+gap)
          print(''.join([FMT2 % (v, "" if (i+1) % col else "\n") for i, v in enumerate(list)]))
      

      然后这里是 better 方法,它可以关闭整个列表的恒定宽度,而不是跨列优化它,限制列数以适应最大值每行字符或找到适合每行最大字符的最佳列数,然后强制左对齐或右对齐,并且仍然可以采用可选的格式字符串,以及每列之间的间隙宽度。

      def printList2(list, col=None, gap=2, uniform=True, ljust=True, STR_FMT="{}", MAX_CHARS=120, end='\n'):
         list = [STR_FMT.format(x).strip() for x in list]
         Lmax, valid, valid_prev, cp, c = [MAX_CHARS+1], None, None, 1, max(col,1) if col else 1
         LoL_prev, Lmax_prev = [], []
      
         while True:
             LoL = [list[i::c] for i in range(c)]
             Lmax = [max(len(x)+gap for x in L) for L in LoL]    # Find max width of each column with gap width
             if uniform:                                         # Set each max column width to max across entire set.
                 Lmax = [max(Lmax) for m in Lmax]
      
             valid_prev, valid = valid, sum(Lmax) <= MAX_CHARS
      
             if (col and (valid or (c == 1))) or not MAX_CHARS:  # If column and valid strlen or MAX_CHARS is empty
                 break
             elif valid_prev and not valid_prev == valid:        # If valid_prev exist
                 c = cp if valid_prev and not valid else c
                 LoL, Lmax = (LoL_prev, Lmax_prev) if valid_prev else (LoL, Lmax)
                 break
      
             LoL_prev, Lmax_prev = LoL, Lmax
             cp, c = c, (c + (+1 if valid else -1))
        
         ljust = '-' if ljust else ''
         FMT = ["%%%s%ds%s" % (ljust, max(Lmax) if uniform else m, end if i+1 == c else '') for i, m in enumerate(Lmax)]
         outStr = ''.join([''.join([f % v for v, f in zip(L, FMT)]) for L in zip(*LoL)])
         remStr = ''.join([f % v for v, f in zip(list[c * (len(list) // c):], FMT)])
         print(outStr+(remStr+end if remStr else remStr), end='')
      

      带输出的测试:

      >>> foolist = ['exiv2-devel', 'mingw-libs', 'tcltk-demos', 'fcgi', 'netcdf',
                   'pdcurses-devel', 'msvcrt', 'gdal-grass', 'iconv', 'qgis-devel', 
                   'qgis1.1', 'php_mapscript']
      >>> printList2(foolist)
      exiv2-devel     mingw-libs      tcltk-demos     fcgi            netcdf          pdcurses-devel  msvcrt          
      gdal-grass      iconv           qgis-devel      qgis1.1         php_mapscript   
      
      >>> printList2(foolist, MAX_CHARS=48, uniform=False, gap=3)
      exiv2-devel   mingw-libs   tcltk-demos      
      fcgi          netcdf       pdcurses-devel   
      msvcrt        gdal-grass   iconv            
      qgis-devel    qgis1.1      php_mapscript    
      
      >>> printList2(foolist, col=2, MAX_CHARS=48, uniform=False, gap=3)
      exiv2-devel   mingw-libs       
      tcltk-demos   fcgi             
      netcdf        pdcurses-devel   
      msvcrt        gdal-grass       
      iconv         qgis-devel       
      qgis1.1       php_mapscript    
      
      >>> printList2(foolist, col=2, MAX_CHARS=48, uniform=False, ljust=False, gap=2)
        exiv2-devel      mingw-libs
        tcltk-demos            fcgi
             netcdf  pdcurses-devel
             msvcrt      gdal-grass
              iconv      qgis-devel
            qgis1.1   php_mapscript
      
      >>> printList2(foolist, col=10, MAX_CHARS=48, uniform=True, ljust=False, gap=2)
           exiv2-devel      mingw-libs     tcltk-demos
                  fcgi          netcdf  pdcurses-devel
                msvcrt      gdal-grass           iconv
            qgis-devel         qgis1.1   php_mapscript
      
      >>> from math import pi
      >>> FloatList = [pi**(i+1) for i in range(32)]
      >>> printList2(FloatList, STR_FMT="{:.5g},", col=7, ljust=False)
            3.1416,      9.8696,      31.006,      97.409,      306.02,      961.39,      3020.3,
            9488.5,       29809,       93648,   2.942e+05,  9.2427e+05,  2.9037e+06,  9.1222e+06,
        2.8658e+07,  9.0032e+07,  2.8284e+08,  8.8858e+08,  2.7916e+09,    8.77e+09,  2.7552e+10,
        8.6556e+10,  2.7192e+11,  8.5427e+11,  2.6838e+12,  8.4313e+12,  2.6488e+13,  8.3214e+13,
        2.6142e+14,  8.2129e+14,  2.5802e+15,  8.1058e+15,
      

      【讨论】:

        【解决方案5】:

        对于 Python >=3.6,使用 f-strings@JoshuaZastrow 的答案进行轻微更新并添加 clear 方法来调整列

        cols = 5
        [print(f'{key:20}', end='\t') if (idx + 1) % cols else print(f'{key}') for idx, key in enumerate(list_variable)]
        

        cols = 5
        for idx, key in enumerate(list_variable):
            if (idx + 1) % cols:
                print(f'{key:20}', end='\t')
            else:
                print(f'{key}')
        

        【讨论】:

          【解决方案6】:

          这个在单独的列中打印列表(保留顺序)

          from itertools import zip_longest
          
          def ls(items, n_cols=2, pad=30):
              if len(items) == 0:
                  return
              total = len(items)
              chunk_size = total // n_cols
              if chunk_size * n_cols < total:
                  chunk_size += 1
              start = range(0, total, chunk_size)
              end = range(chunk_size, total + chunk_size, chunk_size)
              groups = (items[s:e] for s, e in zip(start, end))
              for group in zip_longest(*groups, fillvalue=''):
                  template = (' ').join(['%%-%ds' % pad] * len(group))
                  print(template % group)
          

          用法:

          ls([1, 2, 3, 4, 5, 6, 7], n_cols=3, pad=10)
          

          输出:

          1          4          7         
          2          5                    
          3          6                    
          

          请注意,如果项目数量不足,可能会丢失列,因为先填充列。

          ls([1, 2, 3, 4, 5], n_cols=4)
          

          输出:

          1          3          5         
          2          4    
          

          【讨论】:

            【解决方案7】:

            这是一个简单的方法。解释见内联 cmets:

            import shutil
            import itertools
            from functools import reduce
            
            
            def split_list(lst, ncols):
                """Split list into rows"""
                return itertools.zip_longest(
                    *[lst[i::ncols] for i in range(ncols)], fillvalue=""
                )
                # -- Alternatively --
                # import numpy as np
                # array = np.array(lst)
                # nrows = array.size / ncols + 1
                # return np.array_split(array, int(nrows))
            
            
            def print_in_columns(lst):
                """Print a list in columns."""
                # Find maximum length of a string in colors_list
                colsize = reduce(lambda x, y: max(x, len(y)), lst, 0)
                # Terminal width
                maxcols = shutil.get_terminal_size()[0]
                ncols = maxcols / (colsize + 1)
                rows = split_list(lst, int(ncols))
            
                print(
                    # Join rows
                    "\n".join(
                        (
                            # Fill items left justified
                            " ".join(item.ljust(colsize) for item in row)
                            for row in rows
                        )
                    )
                )
            

            【讨论】:

              【解决方案8】:

              我需要调整每一列。我已经实现了这段代码

              def print_sorted_list(data, columns):
                  if data:
                      gap = 2
                      ljusts = {}
                      for count, item in enumerate(sorted(data), 1):
                          column = count % columns
                          ljusts[column] = len(item) if (column not in ljusts) else max(ljusts[column], len(item))
              
                      for count, item in enumerate(sorted(data), 1):
                          print item.ljust(ljusts[count % columns] + gap),
                          if (count % columns == 0) or (count == len(data)):
                              print
              

              例子:

              foolist = ['exiv2-devel', 'mingw-libs', 'tcltk-demos', 'fcgi', 'netcdf',
                         'pdcurses-devel', 'msvcrt', 'gdal-grass', 'iconv', 'qgis-devel',
                         'qgis1.1', 'php_mapscript', 'blablablablablablabla', 'fafafafafafa']
              print_sorted_list(foolist, 4)
              

              输出:

              blablablablablablabla   exiv2-devel      fafafafafafa    fcgi        
              gdal-grass              iconv            mingw-libs      msvcrt      
              netcdf                  pdcurses-devel   php_mapscript   qgis-devel  
              qgis1.1                 tcltk-demos   
              

              【讨论】:

                【解决方案9】:

                作为@Aman 的扩展,下面是一个函数,它接受一个字符串列表并根据终端大小在列中输出它们。

                import os
                def column_display(input_list):
                    '''
                    Used to create a structured column display based on the users terminal size
                
                    input_list : A list of string items which is desired to be displayed
                    '''
                    rows, columns = os.popen('stty size', 'r').read().split()
                    terminal_space_eighth = int(columns)/8
                    terminal_space_seventh = int(columns)/7
                    terminal_space_sixth = int(columns)/6
                    terminal_space_fifth = int(columns)/5
                    terminal_space_quarter = int(columns)/4
                    terminal_space_third = int(columns)/3
                    terminal_space_half = int(columns)/2
                    longest_string = max(input_list, key=len)
                    longest_length = len(longest_string) + 1
                    list_size = len(input_list)
                
                    if longest_length > terminal_space_half:
                         for string in input_list:
                             print(string)
                    elif terminal_space_eighth >= longest_length and list_size >= 8:
                         for a,b,c,d,e,f,g,h in zip(input_list[::8],input_list[1::8],input_list[2::8], input_list[3::8], input_list[4::8], input_list[5::8], input_list[6::8], input_list[7::8]):
                             column_space = '{:<%s}{:<%s}{:<%s}{:<%s}{:<%s}{:<%s}{:<%s}{:<}' % (longest_length, longest_length, longest_length, longest_length, longest_length, longest_length, longest_length )
                             output = column_space.format(a,b,c,d,e,f,g,h)
                             print(output)
                    elif terminal_space_seventh >= longest_length and list_size >= 7:
                        for a,b,c,d,e,f,g in zip(input_list[::7],input_list[1::7],input_list[2::7], input_list[3::7], input_list[4::7], input_list[5::7], input_list[6::7]):
                             column_space = '{:<%s}{:<%s}{:<%s}{:<%s}{:<%s}{:<%s}{:<}' % (longest_length, longest_length, longest_length, longest_length, longest_length, longest_length)
                             output = column_space.format(a,b,c,d,e,f,g)
                             print(output)
                    elif terminal_space_sixth >= longest_length and list_size >= 6:
                         for a,b,c,d,e,f in zip(input_list[::6],input_list[1::6],input_list[2::6], input_list[3::6], input_list[4::6], input_list[5::6]):
                             column_space = '{:<%s}{:<%s}{:<%s}{:<%s}{:<%s}{:<}' % (longest_length, longest_length, longest_length, longest_length, longest_length)
                             output = column_space.format(a,b,c,d,e,f)
                             print(output)
                    elif terminal_space_fifth >= longest_length and list_size >= 5:
                        for a,b,c,d,e in zip(input_list[::5],input_list[1::5],input_list[2::5], input_list[3::5], input_list[4::5]):
                            column_space = '{:<%s}{:<%s}{:<%s}{:<%s}{:<}' % (longest_length, longest_length, longest_length, longest_length)
                            output = column_space.format(a,b,c,d,e)
                            print(output)
                    elif terminal_space_quarter >= longest_length and list_size >= 4:
                        for a,b,c,d in zip(input_list[::4],input_list[1::4],input_list[2::4], input_list[3::4]):
                            column_space = '{:<%s}{:<%s}{:<%s}{:<}' % (longest_length, longest_length, longest_length)
                            output = column_space.format(a,b,c,d)
                            print(output)
                    elif terminal_space_third >= longest_length and list_size >= 3:
                        for a,b,c in zip(input_list[::3],input_list[1::3],input_list[2::3]):
                            column_space = '{:<%s}{:<%s}{:<}' % (longest_length, longest_length)
                            output = column_space.format(a,b,c)
                            print(output)
                    elif terminal_space_half >= longest_length and list_size >= 2:
                        for a,b in zip(input_list[::2],input_list[1::2]):
                            column_space = '{:<%s}{:<}' % longest_length
                            output = column_space.format(a,b)
                            print(output)
                

                作为解释,它做了一些不同的事情。

                首先它使用 os.popen 获取当前用户终端的列数。

                它取列数并分成两半,增加到八分之一。这将用于比较列表中最长的字符串,以确定最适合此的列数。

                第三个是使用内置 python 函数 max() 拉出的列表中最长的字符串。

                Forth 取最长字符串的长度,然后添加一个用于填充。列表的长度也是如此,因此如果列表少于 8 个项目,它将仅列出存在的项目数。

                第五最长的字符串长度与从一列到八列的每个终端空间进行比较。如果列大于或等于长度,则可以使用它。例如,最长的字符串是 10,列除以 8(terminal_space_eighth) 是 8,但列除以 7(terminal_space_seventh) 是 12,将有 7 列。将有 7 个,因为最长的字符串可以容纳 12 个字符,但不能容纳 8 个字符。

                还值得注意的是,要考虑列表的长度,以防止创建的列多于列表项。

                Sixth 是@Aman 解释的扩展:https://stackoverflow.com/a/1524132/11002603

                索引 为了这个例子,让 i 表示由终端大小确定的数字。 input_list[::i] 这会选择 i 处的元素。在前面添加一个数字,例如 input_list[1::i] 会偏移起点(请记住,python 认为 0 是一个有效数字,这就是它最初不使用的原因。)

                压缩

                Zip 用于创建包含列表元素的元组。例如,输出列表将如下所示

                zip([string1,string2,string3], [string4,string5, string6], [string7,string8,string9])
                output : [(string1,string4,string7), (string2,string5, string8), (string3,string6,string9)]
                

                一起使用 根据列数,字母仅用于表示拆分。因此,例如,如果终端中只有 5 列,将使用以下内容

                for a,b,c,d,e in zip(input_list[::5],input_list[1::5],input_list[2::5], input_list[3::5], input_list[4::5]):
                

                这将获取通过压缩创建的元组,然后存储为 a、b、c、d 和 e 变量,以便我们可以在循环中调用它们。

                列空间随后用于将 a、b、c、d 和 e 中的每一个格式化为各自的列,并且是确定每列长度的地方。长度基于上面确定的字符串长度。

                【讨论】:

                • 请解释一下您的解决方案,不要只是粘贴 400 行代码“答案”。只需包含内联 cmets
                • @thefolenangel 是的,抱歉!我不是故意在制作 cmets 之前发布的。现在添加了一些解释。
                【解决方案10】:

                已经有很多答案了,但我将分享我的解决方案,除了将列表打印成多列之外,它还可以从终端宽度和列表中最长的字符串中动态选择列的数量。

                import os
                cols = os.popen('stty size', 'r').read().split()[1]
                
                def print_multicol(my_list):
                    max_len = len(max(my_list,key=len)) + 2
                    ncols = (int(cols) -4 ) / max_len
                    while my_list:
                        n = 0
                        while n < ncols:
                            if len(my_list) > 0 :
                                fstring = "{:<"+str(max_len)+"}"
                                print fstring.format(my_list.pop(0)),
                            n += 1
                        print
                
                a_list = "a ab abc abcd abcde b bc bcde bcdef c cde cdef cdfg d de defg"
                a_list += "defgh e ef efg efghi efghij f fg fgh fghij fghijk"
                
                print_multicol(a_list.split())
                

                【讨论】:

                  【解决方案11】:
                  [print('{:20}'.format(key), end='\t') if (idx + 1) % 5 else print(key, end='\n') for idx, key in enumerate(list_variable)]
                  

                  for idx, key in enumerate(list_variable):
                      if (idx + 1) % 5:
                          print('{:20}'.format(key), end='\t')
                      else:
                          print(key, end='\n')
                  

                  【讨论】:

                    【解决方案12】:

                    这样的事情怎么样?

                    def strlistToColumns( strl, maxWidth, spacing=4 ):
                    
                    longest = max([len(s) for s in strl])
                    width = longest+spacing
                    
                    # compute numCols s.t. (numCols-1)*(longest+spacing)+longest < maxWidth
                    numCols = 1 + (maxWidth-longest)//width
                    C = range(numCols)
                    
                    # If len(strl) does not have a multiple of numCols, pad it with empty strings
                    strl += [""]*(len(strl) % numCols)
                    numRows = len(strl)/numCols
                    colString = ''
                    
                    for r in range(numRows):
                        colString += "".join(["{"+str(c)+":"+str(width)+"}" \
                            for c in C]+["\n"]).format(*(strl[numCols*r+c] \
                            for c in C))
                    
                    return colString 
                    
                    
                    if __name__ == '__main__':
                    
                    fruits = ['apple', 'banana', 'cantaloupe', 'durian', 'elderberry',         \
                              'fig', 'grapefruit', 'honeydew', 'indonesian lime', 'jackfruit', \
                              'kiwi', 'lychee', 'mango', 'orange', 'pomegranate', 'quince',    \
                              'raspberry', 'tangerine', 'ugli fruit', 'watermelon', 'xigua',
                              'yangmei', 'zinfandel grape']
                    
                    cols = strlistToColumns( fruits, 80 )
                    
                    print(cols)
                    

                    输出

                    apple              banana             cantaloupe         durian
                    elderberry         fig                grapefruit         honeydew
                    indonesian lime    jackfruit          kiwi               lychee
                    mango              orange             pomegranate        quince
                    raspberry          tangerine          ugli fruit         watermelon
                    xigua              yangmei            zinfandel grape
                    

                    【讨论】:

                      【解决方案13】:

                      允许不均匀的列很有用,而不必事先知道可以容纳多少列:

                      >>> words = [string.ascii_lowercase] + list(string.ascii_lowercase)
                      >>> print format_list(words)
                      abcdefghijklmnopqrstuvwxyz  b  d  f  h  j  l  n  p  r  t  v  x  z
                      a                           c  e  g  i  k  m  o  q  s  u  w  y
                      

                      你的例子:

                      >>> foolist = ['exiv2-devel', 'mingw-libs', 'tcltk-demos', 'fcgi',
                      ... 'netcdf', 'pdcurses-devel', 'msvcrt', 'gdal-grass', 'iconv',
                      ... 'qgis-devel', 'qgis1.1', 'php_mapscript']
                      >>> print format_list(foolist, spacing=4, width=31)
                      exiv2-devel       msvcrt
                      mingw-libs        gdal-grass
                      tcltk-demos       iconv
                      fcgi              qgis-devel
                      netcdf            qgis1.1
                      pdcurses-devel    php_mapscript
                      

                      这里是代码。请注意,它还可以处理带有 ANSI 颜色代码(例如来自 colorama 包)的单词——它们不会弄乱列宽。

                      ansi_pattern = re.compile(r'\x1b\[\d{1,2}m')
                      
                      
                      def get_nchars(string):
                          """Return number of characters, omitting ANSI codes."""
                          return len(ansi_pattern.sub('', string))
                      
                      
                      def format_list(items, indent=0, spacing=2, width=79):
                          """Return string listing items along columns.
                      
                          items : sequence
                              List of items to display that must be directly convertible into
                              unicode strings. ANSI color codes may be present, and are taken
                              into account in determining column widths
                          indent : int
                              Number of spaces in left margin.
                          spacing : int
                              Number of spaces between columns.
                          width : int
                              Maximum number of characters per line, including indentation.
                          """
                          if not items:
                              return u''
                          # Ensure all items are strings
                          items = [unicode(item) for item in items]
                          # Estimate number of columns based on shortest and longest items
                          minlen = min(get_nchars(item) for item in items)
                          maxlen = max(get_nchars(item) for item in items)
                          # Assume one column with longest width, remaining with shortest.
                          # Use negative numbers for ceiling division.
                          ncols = 1 - (-(width - indent - maxlen) // (spacing + min(1, minlen)))
                          ncols = max(1, min(len(items), ncols))
                      
                          # Reduce number of columns until items fit (or only one column)
                          while ncols >= 1:
                              # Determine number of rows by ceiling division
                              nrows = -(-len(items) // ncols)
                              # Readjust to avoid empty last column
                              ncols = -(-len(items) // nrows)
                              # Split items into columns, and test width
                              columns = [items[i*nrows:(i+1)*nrows] for i in range(ncols)]
                              totalwidth = indent - spacing + sum(
                                  spacing + max(get_nchars(item) for item in column)
                                  for column in columns
                                  )
                              # Stop if columns fit. Otherwise, reduce number of columns and
                              # try again.
                              if totalwidth <= width:
                                  break
                              else:
                                  ncols -= 1
                      
                          # Pad all items to column width
                          for i, column in enumerate(columns):
                              colwidth = max(get_nchars(item) for item in column)
                              columns[i] = [
                                  item + ' ' * (colwidth - get_nchars(item))
                                  for item in column
                                  ]
                      
                          # Transpose into rows, and return joined rows
                          rows = list(itertools.izip_longest(*columns, fillvalue=''))
                          return '\n'.join(
                              ' ' * indent + (u' ' * spacing).join(row).rstrip()
                              for row in rows
                              )
                      

                      【讨论】:

                        【解决方案14】:

                        我将n 列解决方案扩展到@Aman 的答案

                        def printMultiCol(l, n_cols, buffer_len=5):
                            """formats a list of strings, l, into n_cols with a separation of buffer_len"""
                            if not l: return [] # return if not iterable!
                            max_l = max(map(len, l))
                            formatter = '{{:<{max_l}}}'.format(max_l=max_l+buffer_len)*n_cols
                            zip_me_up = [l[i::n_cols] for i in xrange(n_cols)]
                            max_zip_l = max(map(len, zip_me_up))
                            zip_me_up = map(lambda x: x + ['']*(max_zip_l-len(x)), zip_me_up)
                            return [formatter.format(*undress_me) for undress_me in zip(*zip_me_up)]
                        

                        测试

                        使用随机字符串长度设置测试

                        import random
                        list_length = 16
                        random_strings = [
                            ''.join(random.choice('spameggsbaconbeanssausage') 
                            for x in range(random.randint(1,10)))
                            for i in xrange(list_length)
                        ]
                        
                        print 'for 4 columns (equal length cols) ...\n{}'.format(
                            '\n'.join(printMultiCol(random_strings, 4))
                        )
                        print 'for 7 columns (odd length cols) ...\n{}'.format(
                            '\n'.join(printMultiCol(random_strings, 5))
                        )
                        

                        返回

                        ## -- End pasted text --
                        for 4 columns (equal length cols) ...
                        sgsebpasgm     assgaesse      ossmeagan      ebesnagec
                        mees           eeges          m              gcb
                        sm             pbe            bbgaa          ganopabnn
                        bmou           asbegu         a              psoge
                        
                        
                        for 7 columns (odd length cols) ...
                        sgsebpasgm     assgaesse      ossmeagan      ebesnagec      mees
                        eeges          m              gcb            sm             pbe
                        bbgaa          ganopabnn      bmou           asbegu         a
                        psoge
                        

                        【讨论】:

                          【解决方案15】:

                          灵感来自 gimel 的回答 above

                          import math
                          
                          def list_columns(obj, cols=4, columnwise=True, gap=4):
                              """
                              Print the given list in evenly-spaced columns.
                          
                              Parameters
                              ----------
                              obj : list
                                  The list to be printed.
                              cols : int
                                  The number of columns in which the list should be printed.
                              columnwise : bool, default=True
                                  If True, the items in the list will be printed column-wise.
                                  If False the items in the list will be printed row-wise.
                              gap : int
                                  The number of spaces that should separate the longest column
                                  item/s from the next column. This is the effective spacing
                                  between columns based on the maximum len() of the list items.
                              """
                          
                              sobj = [str(item) for item in obj]
                              if cols > len(sobj): cols = len(sobj)
                              max_len = max([len(item) for item in sobj])
                              if columnwise: cols = int(math.ceil(float(len(sobj)) / float(cols)))
                              plist = [sobj[i: i+cols] for i in range(0, len(sobj), cols)]
                              if columnwise:
                                  if not len(plist[-1]) == cols:
                                      plist[-1].extend(['']*(len(sobj) - len(plist[-1])))
                                  plist = zip(*plist)
                              printer = '\n'.join([
                                  ''.join([c.ljust(max_len + gap) for c in p])
                                  for p in plist])
                              print printer
                          

                          结果(第二个满足您的要求):

                          >>> list_columns(foolist)
                          exiv2-devel       fcgi              msvcrt            qgis-devel        
                          mingw-libs        netcdf            gdal-grass        qgis1.1           
                          tcltk-demos       pdcurses-devel    iconv             php_mapscript     
                          
                          >>> list_columns(foolist, cols=2)
                          exiv2-devel       msvcrt            
                          mingw-libs        gdal-grass        
                          tcltk-demos       iconv             
                          fcgi              qgis-devel        
                          netcdf            qgis1.1           
                          pdcurses-devel    php_mapscript     
                          
                          >>> list_columns(foolist, columnwise=False)
                          exiv2-devel       mingw-libs        tcltk-demos       fcgi              
                          netcdf            pdcurses-devel    msvcrt            gdal-grass        
                          iconv             qgis-devel        qgis1.1           php_mapscript     
                          
                          >>> list_columns(foolist, gap=1)
                          exiv2-devel    fcgi           msvcrt         qgis-devel     
                          mingw-libs     netcdf         gdal-grass     qgis1.1        
                          tcltk-demos    pdcurses-devel iconv          php_mapscript  
                          

                          【讨论】:

                          • 建议 str(c).ljust,因为 c.ljust 不适用于我的列表项。在最后第三行,还有 len(str(item)),以同样的方式预先计算长度。
                          • @ErikKruus 谢谢,已对此进行了编辑。我现在正在从转换为字符串的传入 obj 创建一个新列表。防止需要多个 str() 并保护传入的对象不被编辑。
                          【解决方案16】:

                          发现这个问题几乎是相同的任务。而且我创建了以列数作为参数的多列打印列表的功能。也许没有单线解决方案那么优雅,但它可能对某人有用。

                          但是,它可以处理不完整的列表,例如:它可以打印 3 行中的 11 个列表。

                          功能拆分以提高可读性:

                          def is_printable(my_list):
                              return len(my_list) > 0
                          
                          def create_empty_list(columns):
                              result = []
                              for num in range(0, columns):
                                  result.append([])
                              return result
                          
                          def fill_empty_list(empty_list, my_list, columns):
                              column_depth = len(my_list) / columns if len(my_list) % columns == 0 else len(my_list) / columns + 1
                              item_index = 0
                              for column in range(0, columns):
                                  while len(empty_list[column]) < column_depth:
                                      if item_index < len(my_list):
                                          empty_list[column].append(my_list[item_index])
                                      else:
                                          empty_list[column].append(" ")  # last column could be incomplete, fill it with space
                                      item_index += 1
                          
                          def print_list_in_columns(my_list, columns=1):
                              if not is_printable(my_list):
                                  print 'Nothing to print, sorry...'
                                  return
                              column_width = 25  #(in symbols) Also can be calculated automatically  
                              list_to_print = create_empty_list(columns)
                              fill_empty_list(list_to_print, my_list, columns)
                              iterators = ["it" + str(i) for i in range(0, columns)]
                              for iterators in zip(*list_to_print):
                                  print ("".join(str.ljust(i, column_width) for i in iterators))
                          

                          和调用部分:

                          foolist = ['exiv2-devel', 'mingw-libs', 'tcltk-demos', 'fcgi', 'netcdf', 
                              'pdcurses-devel',     'msvcrt', 'gdal-grass', 'iconv', 'qgis-devel', 
                              'qgis1.1', 'php_mapscript']
                          
                          print_list_in_columns(foolist, 2)
                          

                          【讨论】:

                            【解决方案17】:

                            这是 python 3.4 中的一个解决方案,它可以自动检测终端宽度并将其考虑在内。在 Linux 和 Mac 上测试。

                            def column_print(list_to_print, column_width=40):
                                import os
                                term_height, term_width = os.popen('stty size', 'r').read().split()
                                total_columns = int(term_width) // column_width
                                total_rows = len(list_to_print) // total_columns
                                # ceil
                                total_rows = total_rows + 1 if len(list_to_print) % total_columns != 0 else total_rows
                            
                                format_string = "".join(["{%d:<%ds}" % (c, column_width) \
                                        for c in range(total_columns)])
                                for row in range(total_rows):
                                    column_items = []
                                    for column in range(total_columns):
                                        # top-down order
                                        list_index = row + column*total_rows
                                        # left-right order
                                        #list_index = row*total_columns + column
                                        if list_index < len(list_to_print):
                                            column_items.append(list_to_print[list_index])
                                        else:
                                            column_items.append("")
                                    print(format_string.format(*column_items))
                            

                            【讨论】:

                              【解决方案18】:

                              这是我的解决方案。 (Copy in GitHub gist)

                              它将终端宽度作为输入,并仅显示可以容纳的列数。

                              def col_print(lines, term_width=80, indent=0, pad=2):
                                n_lines = len(lines)
                                if n_lines == 0:
                                  return
                              
                                col_width = max(len(line) for line in lines)
                                n_cols = int((term_width + pad - indent)/(col_width + pad))
                                n_cols = min(n_lines, max(1, n_cols))
                              
                                col_len = int(n_lines/n_cols) + (0 if n_lines % n_cols == 0 else 1)
                                if (n_cols - 1) * col_len >= n_lines:
                                  n_cols -= 1
                              
                                cols = [lines[i*col_len : i*col_len + col_len] for i in range(n_cols)]
                              
                                rows = list(zip(*cols))
                                rows_missed = zip(*[col[len(rows):] for col in cols[:-1]])
                                rows.extend(rows_missed)
                              
                                for row in rows:
                                  print(" "*indent + (" "*pad).join(line.ljust(col_width) for line in row))
                              

                              【讨论】:

                                【解决方案19】:

                                这个答案在@Aaron Digulla 的答案中使用了相同的方法,只是使用了更多的 Pythonic 语法。这可能会使上面的一些答案更容易理解。

                                >>> for a,b,c in zip(foolist[::3],foolist[1::3],foolist[2::3]):
                                >>>     print '{:<30}{:<30}{:<}'.format(a,b,c)
                                
                                exiv2-devel                   mingw-libs                    tcltk-demos
                                fcgi                          netcdf                        pdcurses-devel
                                msvcrt                        gdal-grass                    iconv
                                qgis-devel                    qgis1.1                       php_mapscript
                                

                                这可以很容易地适应任意数量的列或可变列,这将导致类似于@gnibbler 的答案。可以根据屏幕宽度调整间距。


                                更新:按要求解释。

                                索引

                                foolist[::3] 选择foolist 的每三个元素。 foolist[1::3] 选择每三个元素,从第二个元素开始('1',因为 python 使用零索引)。

                                In [2]: bar = [1,2,3,4,5,6,7,8,9]
                                In [3]: bar[::3]
                                Out[3]: [1, 4, 7]
                                

                                压缩

                                压缩列表(或其他可迭代对象)生成列表元素的元组。例如:

                                In [5]: zip([1,2,3],['a','b','c'],['x','y','z'])
                                Out[5]: [(1, 'a', 'x'), (2, 'b', 'y'), (3, 'c', 'z')]
                                

                                一起

                                将这些想法放在一起,我们得到了解决方案:

                                for a,b,c in zip(foolist[::3],foolist[1::3],foolist[2::3]):
                                

                                这里我们首先生成foolist 的三个“切片”,每个切片由每三分之一元素索引并偏移一个。单独地,它们每个只包含列表的三分之一。现在,当我们压缩这些切片并迭代时,每次迭代都会为我们提供foolist 的三个元素。

                                这是我们想要的:

                                In [11]: for a,b,c in zip(foolist[::3],foolist[1::3],foolist[2::3]):
                                   ....:      print a,b,c                           
                                Out[11]: exiv2-devel mingw-libs tcltk-demos
                                         fcgi netcdf pdcurses-devel
                                        [etc]
                                

                                代替:

                                In [12]: for a in foolist: 
                                   ....:     print a
                                Out[12]: exiv2-devel
                                         mingw-libs
                                         [etc]
                                

                                【讨论】:

                                • 您能否详细说明 zip(foolist...) 中发生了什么?
                                • 根据@matt wilkie 的要求添加了解释
                                • 当人们说 Python 是最好的学习语言时,我总是觉得很有趣,因为它非常易读。然而,他们编写的代码越像“Pythonic”,就越难理解。
                                • 唯一的问题是它只会打印出可被 3 整除的列表。如果此列表中有 13 项,则不会打印最后一项。
                                【解决方案20】:

                                简单:

                                l = ['exiv2-devel', 'mingw-libs', 'tcltk-demos', 'fcgi', 'netcdf', 
                                    'pdcurses-devel',     'msvcrt', 'gdal-grass', 'iconv', 'qgis-devel', 
                                    'qgis1.1', 'php_mapscript']
                                
                                if len(l) % 2 != 0:
                                    l.append(" ")
                                
                                split = len(l)/2
                                l1 = l[0:split]
                                l2 = l[split:]
                                for key, value in zip(l1,l2):
                                    print '%-20s %s' % (key, value)         #python <2.6
                                    print "{0:<20s} {1}".format(key, value) #python 2.6+
                                

                                【讨论】:

                                • 不会产生输出(数据按列主要顺序)。
                                • 我接受这个作为答案,因为我让它在最短的时间内可靠地工作——我能理解它。虽然将动态多列报告作为其他答案会更好,但我无法让它们可靠地工作(可能是因为我无法遵循其中的逻辑)——有时项目会从随着它的增长/缩小列出,或者它们不再在列中排列。谢谢亚伦!
                                【解决方案21】:
                                from itertools import izip_longest, islice
                                L = ['exiv2-devel', 'mingw-libs', 'tcltk-demos', 'fcgi', 'netcdf', 
                                    'pdcurses-devel',     'msvcrt', 'gdal-grass', 'iconv', 'qgis-devel', 
                                    'qgis1.1', 'php_mapscript']
                                
                                def columnize(sequence, columns=2):
                                    size, remainder = divmod(len(sequence), columns)
                                    if remainder: 
                                        size += 1
                                    slices = [islice(sequence, pos, pos + size) 
                                              for pos in xrange(0, len(sequence), size)]
                                    return izip_longest(fillvalue='', *slices)
                                
                                for values in columnize(L):
                                    print ' '.join(value.ljust(20) for value in values)
                                

                                【讨论】:

                                  【解决方案22】:

                                  Aaron 的做法可以处理两个以上的列

                                  
                                  >>> l = ['exiv2-devel', 'mingw-libs', 'tcltk-demos', 'fcgi', 'netcdf', 
                                  ...     'pdcurses-devel',     'msvcrt', 'gdal-grass', 'iconv', 'qgis-devel', 
                                  ...     'qgis1.1', 'php_mapscript']
                                  >>> cols = 4
                                  >>> split=[l[i:i+len(l)/cols] for i in range(0,len(l),len(l)/cols)]
                                  >>> for row in zip(*split):
                                  ...  print "".join(str.ljust(i,20) for i in row)
                                  ... 
                                  exiv2-devel         fcgi                msvcrt              qgis-devel          
                                  mingw-libs          netcdf              gdal-grass          qgis1.1             
                                  tcltk-demos         pdcurses-devel      iconv               php_mapscript       
                                  

                                  【讨论】:

                                  • 如果l的长度不是cols的倍数,可以在末尾加一些空字符串来填充
                                  【解决方案23】:

                                  formatting-a-list-of-text-into-columns

                                  一种通用解决方案,可处理任意数量的列和奇数列表。 制表符分隔列,使用生成器表达式来节省空间。

                                  def fmtcols(mylist, cols):
                                      lines = ("\t".join(mylist[i:i+cols]) for i in xrange(0,len(mylist),cols))
                                      return '\n'.join(lines)
                                  

                                  【讨论】:

                                  • 横向排序,可能不是你想要的
                                  【解决方案24】:

                                  如果数据是你提供的格式,那就有点麻烦

                                  
                                  >>> d = ['exiv2-devel', 'mingw-libs', 'tcltk-demos', 'fcgi', 'netcdf', 
                                  ...     'pdcurses-devel',     'msvcrt', 'gdal-grass', 'iconv', 'qgis-devel', 
                                  ...     'qgis1.1', 'php_mapscript']
                                  >>> print "\n".join("%-20s %s"%(d[i],d[i+len(d)/2]) for i in range(len(d)/2))
                                  exiv2-devel          msvcrt
                                  mingw-libs           gdal-grass
                                  tcltk-demos          iconv
                                  fcgi                 qgis-devel
                                  netcdf               qgis1.1
                                  pdcurses-devel       php_mapscript
                                  

                                  【讨论】:

                                    猜你喜欢
                                    • 1970-01-01
                                    • 1970-01-01
                                    • 1970-01-01
                                    • 1970-01-01
                                    • 1970-01-01
                                    • 2011-08-24
                                    • 2020-04-08
                                    • 1970-01-01
                                    • 2018-07-04
                                    相关资源
                                    最近更新 更多