Reputation: 5974
I have some code to print a dictionary in a certain format. However as the number of channels can vary, I want to change this format. But I wonder if it can be done as an easy adjustment to what I have? Here is the code:
band3={'channel11': [10812, 2162, 1972], 'channel10': [10787, 2157, 1967], 'channel3': [10612, 2122, 1932], 'channel2': [10589, 2117, 1927], 'channel1': [10564, 2112, 1922], 'channel7': [10712, 2142, 1952], 'channel6': [10687, 2137, 1947], 'channel5': [10662, 2132, 1942], 'channel4': [10637, 2127, 1937], 'channel9': [10762, 2152, 1962], 'channel8': [10737, 2147, 1957], 'channel12': [10837, 2167, 1977]}
table = [[], [], [], []]
# can't just sort the channel names because 'channel11' < 'channel2'
channel_numbers = []
for channel_name in band3.keys():
if channel_name.startswith('channel'):
channel_number = int(channel_name[7:])
channel_numbers.append(channel_number)
else:
raise ValueError("channel name doesn't follow pattern")
channel_numbers.sort()
for channel_number in channel_numbers:
channel_data = band2['channel%d' % channel_number]
column =[
'Channel %d' % channel_number,
str(channel_data[0]),
'%s/%s' % (channel_data[1], channel_data[2]),
str(channel_data[3])
]
cell_widths = map(len, column) #9 5 2 9
column_widths = max(cell_widths) # 9 or 10
for i in range(len(cell_widths)): #4
cell = column[i]
padded_cell = cell + ' '*(column_widths-len(cell))
table[i].append(padded_cell)
print('{0} {1}'.format("".ljust(6), ' '.join(table[0])))
print('{0} {1}'.format("UARFCN".ljust(6), ' '.join(table[1])))
print('{0} {1}'.format("DL/UL".ljust(6), ' '.join(table[2])))
print('{0} {1}'.format("RSSI".ljust(6), ' '.join(table[3])))
Here is the output currently:
Channel 1 Channel 2 Channel 3 Channel 4 Channel 5 Channel 6 Channel 7 Channel 8 Channel 9 Channel 10 Channel 11 Channel 12
UARFCN 10564 10589 10612 10637 10662 10687 10712 10737 10762 10787 10812 10837
DL/UL 2112/1922 2117/1927 2122/1932 2127/1937 2132/1942 2137/1947 2142/1952 2147/1957 2152/1962 2157/1967 2162/1972 2167/1977
RSSI 20 0 0 26 32 0 26 0 0 0 0 15
Instead of having all data listed on one long line, I want to change it so that after every 4 elements the next bit of data is printed on a new line.
Channel 1 Channel 2 Channel 3 Channel 4
UARFCN 10564 10589 10612 10637
DL/UL 2112/1922 2117/1927 2122/1932 2127/1937
RSSI 20 0 0 26
Channel 5 Channel 6 Channel 7 Channel 8
UARFCN 10662 10687 10712 10737
DL/UL 2112/1922 2117/1927 2122/1932 2127/1937
RSSI 32 0 26 0
Channel 9 Channel 10 Channel 11 Channel 12
UARFCN 10762 10787 10812 10837
DL/UL 2132/1942 2137/1947 2142/1952 2147/1957
RSSI 0 0 0 15
Edit for Mar:
names = ["", "UARFCN", "DL/UL", "RSSI"]
lwidth = max(len(l) for l in names)
for i in range(0, len(table[0]), 4):
for j, head in enumerate(names):
print(' {0:<{lwidth}} {1}'.format(head, ' '.join(table[j][i:i+4])))
print
Upvotes: 0
Views: 1105
Reputation: 1121854
Did you know that str.format()
can do justifying for you? Adding <6
as a formatting string tells format
to left-adjust your text with spaces to fit in 6 characters: '{0:<6} {1}'
. You can do the same with the rest of your table 'columns', including using variable width formatting.
Moreover you can use descriptive naming in your format, plus use some sequence indexing to form a whole row:
table_row = '{label:<{lwidth}} {row[0]:<{cwidth}} {row[1]:<{cwidth}} {row[2]:<{cwidth}} {row[3]:<{cwidth}}'
to create a four-column formatting with the column width given as parameter cwidth
. I made the label width variable as well, so you can later on tinker with the labels (add more, use verbose labels, etc.) without breaking your layout.
Next, group your data in dictionaries per label for easier processing:
labels = ('', 'UARFCN', 'DL/UL', 'RSSI')
lwidth = max(len(l) for l in labels)
table = []
channel_numbers = [int(cname[7:]) if cname.startswith('channel') else None for cname in band3]
if None in channel_numbers:
raise ValueError("channel name doesn't follow pattern")
channel_numbers.sort()
cwidth = 0
for channel_number in channel_numbers:
channel_data = band2['channel{}'.format(channel_number)]
entry = dict(zip(labels, (
'Channel {}'.format(channel_number),
channel_data[0],
'{}/{}'.format(*channel_data[1:3]),
channel_data[3]
)))
cwidth = max(cwidth, max(len(str(v)) for v in entry.values()))
table.append(entry)
Now we have the table data in a list as dictionary entries; it's easier to group them that way. Next we use the itertools
grouper
recipe:
from itertools import izip_longest
def grouper(iterable, n, fillvalue=None):
"Collect data into fixed-length chunks or blocks"
# grouper('ABCDEFG', 3, 'x') --> ABC DEF Gxx
args = [iter(iterable)] * n
return izip_longest(fillvalue=fillvalue, *args)
# use a empty dictionary as filler at the end
for group in grouper(table, 4, dict.fromkeys(labels, '')):
for label in labels:
print(table_row.format(label=label, cwidth=cwidth, lwidth=lwidth,
row=[entry[label] for entry in group]))
print()
This then outputs (with reconstructed band2
and band3
input):
Channel 1 Channel 2 Channel 3 Channel 4
UARFCN 10564 10589 10612 10637
DL/UL 2112/1922 2117/1927 2122/1932 2127/1937
RSSI 20 0 0 26
Channel 5 Channel 6 Channel 7 Channel 8
UARFCN 10662 10687 10712 10737
DL/UL 2132/1942 2137/1947 2142/1952 2147/1957
RSSI 32 0 26 0
Channel 9 Channel 10 Channel 11 Channel 12
UARFCN 10762 10787 10812 10837
DL/UL 2152/1962 2157/1967 2162/1972 2167/1977
RSSI 0 0 0 15
The dict.fromkeys(labels, '')
default makes sure that if you have one row with fewer than 4 entries in your table, the last column(s) are filled with empty strings:
Channel 1 Channel 2 Channel 3 Channel 4
UARFCN 10564 10589 10612 10637
DL/UL 2112/1922 2117/1927 2122/1932 2127/1937
RSSI 20 0 0 26
Channel 5 Channel 6 Channel 7 Channel 8
UARFCN 10662 10687 10712 10737
DL/UL 2132/1942 2137/1947 2142/1952 2147/1957
RSSI 32 0 26 0
Channel 9 Channel 10 Channel 11
UARFCN 10762 10787 10812
DL/UL 2152/1962 2157/1967 2162/1972
RSSI 0 0 0
Upvotes: 2
Reputation: 21595
names = ["", "UARFCN", "DL/UL", "RSSI"]
for i in range(0, len(table[0]), 4):
for j, head in enumerate(names):
print('{0} {1}'.format(head.ljust(6), ' '.join(table[j][i:i+4])) )
print()
Upvotes: 1