1

I am trying to print out a custom format but am facing an issue.

header = ['string', 'longer string', 'str']
header1, header2, header3 = header
data = ['string', 'str', 'longest string']
data1, data2, data3 = data
len1 = len(header1)
len2 = len(header2)
len3 = len(header3)
len_1 = len(data1)
len_2 = len(data2)
len_3 = len(data3)
un = len1 + len2 + len3 + len_1 + len_2 + len_3
un_c = '_' * un
print(f"{un_c}\n|{header1} |{header2} |{header3}| \n |{data1} |{data2} |{data3}|")

Output:

_____________________________________________
|string |longer string |str|
 |string |str |longest string|

The output I want is this:

_______________________________________
|string |longer string |str           |
|string |str           |longest string|

I want it to work for all lengths of strings using the len to add extra spacing to each string to make it aligned, but I can't figure it out at all.

  • Use `\t` instead of spaces for proper spacing. Also, remove the space after newline so that the starting point of second line is not messed up – pptx704 Jul 06 '22 at 23:43
  • `\t` is not always the right solution. In his example, the string lengths vary by more than 8 characters. – Tim Roberts Jul 06 '22 at 23:52

4 Answers4

2

There is a package called tabulate this is very good for this (https://pypi.org/project/tabulate/). Similar post here.

1

Do it in two parts. First, figure out the size of each column. Then, do the printing based on those sizes.

header = ['string','longer string','str']
data = ['string','str','longest string']
lines = [header] * 3 + [data] * 3

def getsizes(lines):
    maxn = [0] * len(lines[0])
    for row in lines:
        for i,col in enumerate(row):
            maxn[i] = max(maxn[i], len(col)+1)
    return maxn

def maketable(lines):
    sizes = getsizes(lines)
    all = sum(sizes)
    print('_'*(all+len(sizes)) )
    for row in lines:
        print('|',end='')
        for width, col in zip( sizes, row ):
            print( col.ljust(width), end='|' )
        print()

maketable(lines)

Output:

_______________________________________
|string |longer string |str            |
|string |longer string |str            |
|string |longer string |str            |
|string |str           |longest string |
|string |str           |longest string |
|string |str           |longest string |

You could change it to build up a single string, if you need that.

Tim Roberts
  • 48,973
  • 4
  • 21
  • 30
1

It accept an arbitrary number of rows. Supposed each row has string-type terms.

def table(*rows, padding=2, sep='|'):
    sep_middle = ' '*(padding//2) + sep + ' '*(padding//2)
    template = '{{:{}}}'

    col_sizes = [max(map(len, col)) for col in zip(*rows)]

    table_template = sep_middle.join(map(template.format, col_sizes))

    print('_' * (sum(col_sizes) + len(sep_middle)*(len(header)-1) + 2*len(sep) + 2*(len(sep)*padding//2)))
    for line in (header, *rows):
        print(sep + ' ' * (padding//2) + table_template.format(*line) + ' ' * (padding//2) + sep)


header = ['string', 'longer string', 'str', '21']
data1 = ['string', 'str', 'longest stringhfykhj', 'null']
data2 = ['this', 'is', 'a', 'test']

# test 1
table(header, data1, data2)

# test 2
table(header, data1, data2, padding=4, sep=':')

Output

# first test
________________________________________________________
| string | longer string | str                  | 21   |
| string | longer string | str                  | 21   |
| string | str           | longest stringhfykhj | null |
| this   | is            | a                    | test |

# second test
________________________________________________________________
:  string  :  longer string  :  str                   :  21    :
:  string  :  longer string  :  str                   :  21    :
:  string  :  str            :  longest stringhfykhj  :  null  :
:  this    :  is             :  a                     :  test  :
cards
  • 3,936
  • 1
  • 7
  • 25
1

Each cell is constructed according to the longest content, with additional spaces for any shortfall, printing a | at the beginning of each line, and the rest of the | is constructed using the end parameter of print

The content is placed in a nested list to facilitate looping, other ways of doing this are possible, the principle is the same and adding some content does not affect it

items = [
    ['string', 'longer string', 'str'],
    ['string', 'str', 'longest string'],
    ['longer string', 'str', 'longest string'],
]
length = [max([len(item[i]) for item in items]) for i in range(len(items[0]))]
max_length = sum(length)

print("_" * (max_length + 4))
for item in items:
    print("|", end="")
    for i in range(len(length)):
        item_length = len(item[i])

        if length[i] > len(item[i]):
            print(item[i] + " " * (length[i] - item_length), end="|")
        else:
            print(item[i], end="|")
    print()

OUTPUT:

____________________________________________
|string       |longer string|str           |
|string       |str          |longest string|
|longer string|str          |longest string|
maya
  • 1,029
  • 1
  • 2
  • 7