2

I'm trying to write a list to rows with a specific number of columns. For example, take the list:

data = [1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0]

I would like to write this out with a format such that it looks like:

 1.0,  2.0,  3.0,
 4.0,  5.0,  6.0,
 7.0,  8.0,  9.0,
10.0,

I've tried the following code; however, can only get it to print the first line:

strformat = ['{'+str(i)+':>5.1f},' for i in range(0,3)]
strformat = ''.join(strformat).lstrip().rstrip() + '\n'
print strformat.format(*[x for x in data])

Thanks in advance!

Bernhard Barker
  • 54,589
  • 14
  • 104
  • 138
user8675309
  • 181
  • 2
  • 10

4 Answers4

1
def chunks(seq, n):
    # http://stackoverflow.com/a/312464/190597 (Ned Batchelder)
    """ Yield successive n-sized chunks from seq."""
    for i in xrange(0, len(seq), n):
        yield seq[i:i + n]

data = [1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0]
for row in chunks(data, 3):
    print(',  '.join(map(str, row)))

yields

1.0,  2.0,  3.0
4.0,  5.0,  6.0
7.0,  8.0,  9.0
10.0

Or, perhaps closer to your code:

strformat = '\n'.join(
    ',  '.join('{:>5.1f}' for item in row) 
    for row in chunks(data, 3))
print(strformat.format(*data))
unutbu
  • 842,883
  • 184
  • 1,785
  • 1,677
  • can't we just use generator statement instead of `chunks`? – oleg Sep 20 '13 at 22:18
  • @oleg: Sure we can! But I don't like looking at the nitty-gritty details inside chunk. When I read code, I want to see the intent, not the implementation. Since the desire to chunk-things-up is so common-place, I'd rather codify it in a utility function. – unutbu Sep 20 '13 at 22:20
  • Another reason to use `chunks` is if at some point the user wants 4 columns instead of 3, you only have to change the number in one place instead of two, thus eliminating the potential source of a bug. – unutbu Sep 20 '13 at 23:40
1

So, you're actually trying to do two things here.

First, you're trying to columnize your list (transform it to a new structure that has three elements in each item). You can write a function that looks a bit like this:

def columnize(data, columns):
    for i in xrange(0, len(data), columns):
        yield data[i:i+columns]

Then you're looking to print them with a specified format. What you have is workable, but you can make it a little simpler by skipping the positional arguments. Instead of '{0} {1} {2}', you can actually just supply '{} {} {}' because the arguments are formatted in order. The printing code would look like:

columns = 3
for row in columnize(data, columns):
    strformat = '{:>5.1f},' * len(row)
    print strformat.format(*row)

Note that we can handle the case of the last row just by using the string multiplication operator; most times, row will have 3 items, but on the last one it has just one.

Steve Howard
  • 6,737
  • 1
  • 26
  • 37
1

Well, this is a fairly simple way; splitting the list at regular intervals. It also prints with right alignment, depending on the length of the longest item in the list. Not very terribly concise, but it seems to me like what you're after.

data = [1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0]
width = 3

table = [data[x:x+width] for x in range(0, len(data), width)]
alignment = len(str(max(data)))

for i in table:
    for j in i:
        print "%s," % str(j).rjust(alignment),
    print

 1.0,  2.0,  3.0,
 4.0,  5.0,  6.0,
 7.0,  8.0,  9.0,
10.0,

And with longer items:

   1.0,    2.0,    3.0,
 400.0, 5000.0,    6.0,
   7.0,    8.0,    9.0,
  10.0,
Jollywatt
  • 1,382
  • 2
  • 12
  • 31
0

I love Joseph's solution, maybe just...

print "%s," % str(j).rjust(alignment, ' '),

Community
  • 1
  • 1
Deja Vu
  • 721
  • 1
  • 8
  • 17