Print a list in multicolumn format

Updated Gribouillis 3 Tallied Votes 2K Views Share

This snippet prints a python list of strings in multicolumn format (similarly to linux ls command). It uses module prettytable, available in pypi.

# python 2 or 3
# Author: Gribouillis for the python forum at www.daniweb.com
# licence: public domain
# use this code freely.
# 03 Mar '15: version 0.2.1, bug fix for empty list and added file, flush args.
# 21 Dec '13: version 0.1, bug fix and added re-calculation of ncols.
from __future__ import print_function
from distutils.version import StrictVersion # pep 386
import prettytable as ptt # pip install prettytable
import sys
assert StrictVersion(ptt.__version__) >= StrictVersion('0.7') # for PrettyTable.vrules property

__version__ = '0.2.1'

def example_list():
    """Return sorted list of python module names"""
    import pkgutil
    L = list(sys.builtin_module_names)
    L.extend(t[1] for t in pkgutil.iter_modules())
    return sorted(L)

def print_multicolumn(alist, ncols, vertically=True, file=None, flush=False):
    """Print a list of strings in several columns
    
    alist: the list to print
    ncols: the desired number of columns in output
    vertically: whether the list items must be enumerated column by
                column or row by row, defaults to True.
    file: a file-like object (stream), defaults to sys.stdout.
    flush: whether to forcibly flush the stream, defaults to False.
    """
    L = alist
    if not L:
        if flush(): file.flush()
        return
    # incompressible number of rows without adding columns.
    nrows = - ((-len(L)) // ncols)
    # the number of columns may be reducible for that many rows.
    ncols = - ((-len(L)) // nrows)
    t = ptt.PrettyTable([str(x) for x in range(ncols)])
    t.header = False
    t.align = 'l'
    t.hrules = ptt.NONE
    t.vrules = ptt.NONE
    r = nrows if vertically else ncols
    chunks = [L[i:i+r] for i in range(0, len(L), r)]
    chunks[-1].extend('' for i in range(r - len(chunks[-1])))
    if vertically:
        chunks = zip(*chunks)
    for c in chunks:
        t.add_row(c)
    if file is None: file = sys.stdout
    print(t, file=file)
    if flush: file.flush()
    
if __name__ == '__main__':
    L = example_list()
    print_multicolumn(L, 4, vertically = True)
	
""" my output -->
  CDROM                 aifc              heapq                   readline       
  CommandNotFound       antigravity       hmac                    reprlib        
  DLFCN                 apt               html                    resource       
  DistUpgrade           apt_clone         http                    rlcompleter    
  IN                    apt_inst          icu                     runpy          
  LanguageSelector      apt_pkg           idlelib                 sandbox    
  ...
"""
Gribouillis 1,391 Programming Explorer Team Colleague

This can actually be used to mimick the action of the ls command with colorful output. The following code lists the user's home directory with colors:

from termcolor import colored # pip install termcolor
import sys
if sys.platform == 'win32':
    from colorama import init # pip install colorama
    init()
import os
import stat

def color_code(filename):
    try:
        mode = os.lstat(filename).st_mode
    except OSError:
        return
    if stat.S_ISDIR(mode):
        return 'blue'
    elif stat.S_ISLNK(mode):
        return 'cyan'
    elif stat.S_ISFIFO(mode) or stat.S_ISBLK(mode):
        return 'yellow'
    elif mode & (stat.S_IXUSR):
        return 'green'
    elif filename.endswith((".tar", ".zip", ".deb", ".rpm", ".gz")):
        return 'red'
    elif filename.endswith((".jpg", ".gif", ".png", ".tiff", ".mp3", ".ogg", ".wav")):
        return 'magenta'

def listdir_color(directory):
    L = sorted(os.listdir(directory), key = lambda s: s.lower())
    for i, name in enumerate(L):
        fn = os.path.join(directory, name)
        col = color_code(fn)
        if col is not None:
            L[i] = colored(name, col)
    return L

if __name__ == '__main__':
    L = listdir_color(os.path.expanduser('~'))
    print_multicolumn(L, 4)

It even works in the ipython notebook !

Also notice that (partial) pure python implementations of ls already exist. See the pycoreutils package :)

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.