Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Python format print with a list

Which is the most pythonic way to produce my output. Let me illustrate the behavior I'm trying to achieve. For a project of my I'm building a function that takes different parameters to print an the output in columns. Example of the list its receives.

[('Field', 'Integer', 'Hex'), 
('Machine;', 332, '0x14c'), 
('NumberOfSections;', 9, '0x9'), 
('Time Date Stamp;', 4, '0x4'), 
('PointerToSymbolTable;', 126976, '0x1f000')

** The size of items can differ (Only 3 items per tuple now, can be 4 for another list or any number**

The output should be something like this

Field                                                     Integer      Hex           
-------------------------------------------------------------------------------
Machine;                                                  332          0x14c        
NumberOfSections;                                         9            0x9          
Time Date Stamp;                                          4            0x4          
PointerToSymbolTable;                                     126976       0x1f000

For working purposes I created a list which only contains the header fields: This isn't necessary but it made it a little bit easier trying stuff out

Header field is ['Field', 'Integer', 'Hex']  

The first tuple in the list declares the so called "Header fields" as shown in the list example. For this case there are only 3 items, but this can differ from time to time. So I tried to calculate the size of items with:

length_container_header = len(container[0])

This variable can be used to correctly build up the output. Building the header "print" I would build something like this.

print("{:21} {:7} {:7}".format(header_field[0], header_field[1], header_field[2]))

Now this is a manual version on how it should be. As you noticed the header field "Field" is shorter then PointerToSymbolTable in the list. I wrote this function to determine the longest item for each position in the list

container_lenght_list = []    
    local_l = 0    
    for field in range(0, lenght_container_body):
        for item in container[1:]:
            if len(str(item[field])) > local_l:
                local_l = len(str(item[field]))
            else:
                continue
        container_lenght_list.append(str(local_l))
        local_l = 0

Produces a list along the lines like [21, 7, 7] in this occasion. creating the format string can be done pretty simple,

formatstring = ""

for line in lst:
    formatstring+= "{:" + str(line) +"}"

Which produces string:

 {:21}{:7}{:7}

This is the part were a run into trouble, how can I produce the last part of the format string? I tried a nested for loop in the format() function but I ended up with all sort of Errors. I think it can be done with a for loop, I just can't figure out how. If someone could push me in the right direction for the header print I would be very grateful. Once I figured out how to print the header I can pretty much figure out the rest. I hope I explained it well enough

With Kind Regards,

like image 792
See Avatar asked Oct 20 '14 17:10

See


People also ask

Can you print a string with a list in Python?

Convert a list to a string for display : If it is a list of strings we can simply join them using join() function, but if the list contains integers then convert it into string and then use join() function to join them to a string and print the string.

Can you print a list in Python?

One of the standard methods to print a list in Python is using the for loop. You can traverse the list from the 0th index to len(list) and print all the elements in the sequence.

What does {} format do in Python?

The format() method formats the specified value(s) and insert them inside the string's placeholder. The placeholder is defined using curly brackets: {}.


2 Answers

You can use * to unpack argument list:

container = [
    ('Field', 'Integer', 'Hex'), 
    ('Machine;', 332, '0x14c'), 
    ('NumberOfSections;', 9, '0x9'), 
    ('Time Date Stamp;', 4, '0x4'), 
    ('PointerToSymbolTable;', 126976, '0x1f000')
]
lengths = [
    max(len(str(row[i])) for row in container) for i in range(len(container[0]))
] # => [21, 7, 7]
# OR  lengths = [max(map(len, map(str, x))) for x in zip(*container)]
fmt = ' '.join('{:<%d}' % l for l in lengths)
# => '{:<21} {:<7} {:<7}'    # < for left-align

print(fmt.format(*container[0]))  # header
print('-' * (sum(lengths) + len(lengths) - 1))  # separator
for row in container[1:]:
    print(fmt.format(*row))  # <------- unpacking argument list
    # similar to   print(fmt.format(row[0], row[1], row[2])

output:

Field                 Integer Hex
-------------------------------------
Machine;              332     0x14c
NumberOfSections;     9       0x9
Time Date Stamp;      4       0x4
PointerToSymbolTable; 126976  0x1f000
like image 64
falsetru Avatar answered Oct 06 '22 06:10

falsetru


Formatting data in tabular form requires four important steps

  1. Determine the field layout i.e. representing data row wise or column wise. Based on the decision you might need to transpose the data using zip
  2. Determine the field sizes. Unless you wan;t to hard-code the field size (not-recommend), you should actually determine the maximum field size based on the data, allowing customized padding between fields. Generally this requires reading the data and determining the maximum length of the fields [len(max(map(str, field), key = len)) + pad for field in zip(*data)]
  3. Extract the header row. This is easy as it only requires indexing the 0th row i.e. data[0]
  4. Formatting the data. This requires some understanding of python format string

Implementation

class FormatTable(object):
    def __init__(self, data, pad = 2):
        self.data = data
        self.pad = pad
        self.header = data[0]
        self.field_size = [len(max(map(str, field), key = len)) + pad 
                           for field in zip(*data)]
        self.format = ''.join('{{:<{}}}'.format(s) for s in self.field_size)
    def __iter__(self):
        yield ''.join(self.format.format(*self.header))
        yield '-'*(sum(self.field_size) + self.pad * len(self.header))
        for row in data[1:]:
            yield ''.join(self.format.format(*row))

Demo

for row in FormatTable(data):
    print row

Field                  Integer  Hex      
-----------------------------------------------
Machine;               332      0x14c    
NumberOfSections;      9        0x9      
Time Date Stamp;       4        0x4      
PointerToSymbolTable;  126976   0x1f000 
like image 42
Abhijit Avatar answered Oct 06 '22 08:10

Abhijit