chrise
chrise

Reputation: 4253

dynamically building strings 'string'.format()

I am trying to write a function that prints tables of various dimensions. May not be the best attempt the way I did it, but almost there.

Last piece of the puzzle is creating the strings with a variable amount of input lines. Since .format() wants input of the form .format(s1, s2, s3) and does not take a list as in .format( (line) ) I have trouble making this work for variable number of columns. Is there any way to do this (in 2.7) without brute force attempts like eval? I always prefer to not use those when void it.

def print_table(self, lines, sum_columns = [], extra_width = 5):
    maxLength = [0] * len(lines)

    for line in lines:
        maxLength = [max(l1,l2) for l1, l2 in zip(maxLength, [len(str(l)) for l in line])]
    if sum_columns:
        total = [0] * len(lines)
        for line in lines:
            for c in sum_columns:
                total[c-1] += line[c-1]
    string = ''
    for c in xrange(len(maxLength)): string = string + '{%s:%s} ' %(c, maxLength[c] + extra_width)
    string = string[:-1]
    print string
    for line in lines:
        print string.format(XXXXXXXXX)

Upvotes: 1

Views: 264

Answers (1)

Martijn Pieters
Martijn Pieters

Reputation: 1122082

You have multiple options:

  1. format each element of your list, then use str.join() to join those elements into a longer string:

    ''.join(['{0:{1}}'.format(c, width + extra) for c, width in zip(line, maxLength)])
    
  2. Build a dynamic format string (concatenating various {} parts), then apply the list as a sequence of arguments using the *args splat syntax.

    template = ''.join(['{%(i)s:{widths[%(i)s]}}' % {'i': i} for i in range(len(maxLength))])
    for line in lines:
        print template(*line, widths=maxLength)
    

Simplifying your code somewhat:

def print_table(self, lines, sum_columns=None, extra_width=5):
    columns = zip(*lines)

    widths = [max(len(str(l)) for l in column) for column in columns]

    for line in lines:
        print ''.join(['{0:{1}}'.format(c, w + extra_width) for c, w in zip(line, widths)])

    if sum_columns is not None:
        totals = [sum(columns[i]) if i + 1 in sum_columns else 0 for i in range(len(columns))]
        print ''.join(['{0:{1}}'.format(c, w + extra_width) for c, w in zip(totals, widths)])

Upvotes: 2

Related Questions