Reputation: 1207
I've got a function which creates a little star table based on some data collected elsewhere in the program. While the table produces the correct output, since the number of characters in each number changes, it un-aligns the table. For example,
70-78: *****
79-87: ***
88-96: ****
97-105: **
106-114: ******
115-123: ****
Is there any way to align the stars so that the output is something like this:
70-78: *****
79-87: ***
88-96: ****
97-105: **
106-114: ******
115-123: ****
Here's how I currently print the table.
for x in range(numClasses):
print('{0}-{1}: {2}'.format(lower[x],upper[x],"*"*num[x]))
Upvotes: 20
Views: 59209
Reputation: 458
I created a relatively generic function for this kind of task based on the responses above.
def CreateAlignedTableString(table):
"""
Create a nicely formatted table from a list of tuples or a list of lists.
"""
max_col_width = [0]*len(table[0])
for row in table:
for col in range(len(row)):
max_col_width[col] = max(max_col_width[col], len(str(row[col])))
fmt_string = ''
for col in range(len(table[0])):
fmt_string += '{:%d} '%(max_col_width[col]+2)
fmt_string += '\n'
table_str = ''
for row in table:
table_str += fmt_string.format(*row)
return table_str
Upvotes: 0
Reputation: 387607
str.format
already has the possibility to specify alignment. You can do that using {0:>5}
; this would align parameter 0
to the right for 5 characters. We can then dynamically build a format string using the maximum number of digits necessary to display all numbers equally:
>>> lower = [70, 79, 88, 97, 106, 115]
>>> upper = [78, 87, 96, 105, 114, 123]
>>> num = [5, 3, 4, 2, 6, 4]
>>> digits = len(str(max(lower + upper)))
>>> digits
3
>>> f = '{0:>%d}-{1:>%d}: {2}' % (digits, digits)
>>> f
'{0:>3}-{1:>3}: {2}'
>>> for i in range(len(num)):
print(f.format(lower[i], upper[i], '*' * num[i]))
70- 78: *****
79- 87: ***
88- 96: ****
97-105: **
106-114: ******
115-123: ****
Actually, you could even use a single format string here with nested fields:
>>> for i in range(len(num)):
print('{0:>{numLength}}-{1:>{numLength}}: {2}'.format(lower[i], upper[i], '*' * num[i], numLength=digits))
Upvotes: 16
Reputation: 1207
Ok, while the solution I'm using is admittedly ad-hoc, it works, and scales better than the answers so far. Basically it's just the method VR17 suggested, but with a little more so that the tab size scales with the data set, and isn't just hard coded in.
First I made a method that returns the number characters in some number.
def charNum(number):
return math.floor(math.log(number,10)+1)
Then I used the charNum()
function on the last point of my lower
and upper
data sets. Only the last point had to be used on each list because the last point is the biggest number. I then counted the character that weren't numbers(the dash, semicolon, and space), and adjusted accordingly.
So the final tabLength variable looks like this:
tabLength = charNum(lower[-1])+charNum(upper[-1])+3
I then plugged the tabLength
variable into the expandTab()
function to get proper spacing. Here's some example output:
1-11: *******
12-22: *
23-33: ***
34-44: **
45-55: ***
56-66: *
99-249: *****
250-400: ****
401-551: **
552-702: **
703-853: *
854-1004: ***
99-200079: ******
200080-400060: **
400061-600041: ****
600042-800022: **
800023-1000003: *
The only problem I can really see with this is that if I wanted to expand this to a table or something the tabs would be all funky. If I did that though, I'd probably look into ljust
and rjust
which I'm not all that familiar with right now. I'll leave the question open for a little while in case someone comes up with a better answer.
Upvotes: 1
Reputation: 369054
lower = [70, 79, 88, 97, 106]
upper = [78, 87, 105, 114, 123]
num = [5, 3, 4, 2, 6, 4]
for l, u, n in zip(lower, upper, num):
print('{0:<9} {1}'.format('{0}-{1}:'.format(l, u), '*' * n))
http://docs.python.org/3/library/string.html#format-specification-mini-language
Upvotes: 1
Reputation: 5967
Easy way (in your case) would be to put a tab instead of space:
for x in range(numClasses):
print('{0}-{1}:\t{2}'.format(lower[x],upper[x],"*"*num[x]))
Another way would be to use str.ljust
:
for x in range(numClasses):
label = '{0}-{1}:'.format(lower[x], upper[x])
print(label.ljust(10, ' ') + "*" * num[x])
Upvotes: 0
Reputation: 2886
This should do the trick. I assume there are clever ways.
print '70-78:'.ljust(10) + '*****'
You could also use expandtabs()
print ('70-78'+'\t'+ '*****').expandtabs(10)
Upvotes: 13