How can I put words from a list into a table?

Viewed 83

Note: I want to achieve this without using any modules.

My goal is to put all text from a list, and put a table around it. I want to find out how many spaces it needs depending on the length of the word or something like that. I want to know how big the width and height has to be etc. To find out what the width should be, I could find out what the longest word in the list is and and do "─" * len(longestWord). To find out what the height should be, I could find out how many items are in the list and do this

amountInLst = len(lst)

for i in range(0, amountInList):
      print(f"│{lst[i]}│")

But the only thing I don't know how to do is calculate the spaces so theres always 2 spaces left from the left side and right side. If anyone has any ideas or code then please help me.

For example:

Input:

lst = ["England", "France", "Sweden", "Norway", "Russia"]

output:

┌────────────┐
│ England    │
│ France     │
│ Sweden     │
│ Norway     │
│ Russia     │
└────────────┘
3 Answers

To print "border" around words in your list you can do:

lst = ["England", "France", "Sweden", "Norway", "Russia"]

max_len = max(len(w) for w in lst)
f = "{:<" + str(max_len) + "}"

print("┌" + ("─" * (max_len + 2)) + "┐")
for w in lst:
    print("| " + f.format(w) + " |")
print("└" + ("─" * (max_len + 2)) + "┘")

Prints:

┌─────────┐
| England |
| France  |
| Sweden  |
| Norway  |
| Russia  |
└─────────┘

Use the tabulate module.

from tabulate import tabulate
lst = [
      ["Milan", 14, "Male"],
      ["Alex", 482, "Male"],
      ["John", 12, "Male"],
      ["Jake", 36, "Male"],
      ["James", 12, "Male"]
]

print(tabulate(lst, headers=["Name", "Age", "Gender"]))

Solution

You can use the following custom code to display tables without using any other package. However, why reinvent the wheel? If you can, you should either use one of the following:

  • tabulate
  • pandas.Dataframe.to_markdown
  • pandas.Dataframe.to_string

To use the code given below, run this:

_ = maketable(data=lst, headers=headers, headersep='-', showtable=True)

## Output:
| Name  | Age | Gender |
|-------|-----|--------|
| Milan | 14  | Male   |
| Alex  | 482 | Male   |
| John  | 12  | Male   |
| Jake  | 36  | Male   |
| James | 12  | Male   |

Extended Example of Code Usage

lst = [
    ["Milan", 14, "Male"],
    ["Alex", 482, "Male"],
    ["John", 12, "Male"],
    ["Jake", 36, "Male"],
    ["James", 12, "Male"]
]

headers = ['Name', 'Age', 'Gender']

tabeltext = maketable(
    data = lst,                 # the data to create the table 
    headers = headers,          # list of headers
    bufferlen = 1,              # length of buffers spaces to use around each table-cell-value
    headersep = '-',            # seperator-line-character to use between hear row and the rest of the table 
    data_has_header = False,    # if `data` parameter has headers or not
    showtable = True            # whether to print the table or not
)

Code

from typing import List

def get_column_widths(
    data: List[List], 
    headers: List[str] = None, 
    num_cols: int = None) -> List[int]:
    """returns column widths from the table data.

    Example:
        lst = [
            ["Milan", 14, "Male"],
            ["Alex", 482, "Male"],
            ["John", 12, "Male"],
            ["Jake", 36, "Male"],
            ["James", 12, "Male"]
        ]

        headers = ['Name', 'Age', 'Gender']
        get_column_widths(data=lst, headers=headers, num_cols=None)

    """

    if (num_cols is None) and (headers is None):
        num_cols = len(data[0])

    if headers:
        num_cols = len(headers)
        _data = [headers] + data
    else:
        _data = data.copy()

    col_widths = [0 for _ in range(num_cols)]

    for ridx, line in enumerate(_data):
        for cidx, e in enumerate(line):
            col_width = len(str(e))
            if col_width > col_widths[cidx]:
                col_widths[cidx] = col_width

    return col_widths


def pad(text: str, length: int) -> str: 
    return text + ' '*length


def wraptext(text: str, length: int) -> str: 
    return text[:length] + '\n' + text[length:]


def pad_or_wrap(text: str, length: int = 10) -> str:
    n = len(text)
    if n > length:
        text = wraptext(text=text, length=length)
    elif n < length:
        text = pad(text=text, length=length-n)
    return text


def maketable(
    data: List[List], 
    headers: List[str] = None, 
    bufferlen: int = 1, 
    headersep: str = '-', 
    data_has_header: bool = False, 
    showtable: bool=True) -> str:
    """Returns the table as a string.

    Example:
        lst = [
            ["Milan", 14, "Male"],
            ["Alex", 482, "Male"],
            ["John", 12, "Male"],
            ["Jake", 36, "Male"],
            ["James", 12, "Male"]
        ]

        headers = ['Name', 'Age', 'Gender']

        tabeltext = maketable(
            data = lst,                 # the data to create the table 
            headers = headers,          # list of headers
            bufferlen = 1,              # length of buffers spaces to use around each table-cell-value
            headersep = '-',            # seperator-line-character to use between hear row and the rest of the table 
            data_has_header = False,    # if `data` parameter has headers or not
            showtable = True            # whether to print the table or not
        )

    """
    tablerows = []
    bufferlen = 1
    buffertext = '' if bufferlen == 0 else ' ' * bufferlen
    if headers:
        num_cols = len(headers)
        if not data_has_header:
            _data = [headers] + data
    else:
        if data_has_header:
            headers = data[0]
            num_cols = len(headers)
        _data = data.copy()

    col_widths = get_column_widths(data = _data)

    for ridx, line in enumerate(_data):    
        tablerows.append(
            '|' + '|'.join(
                buffertext + \
                pad_or_wrap(text = str(e), 
                            length = col_widths[cidx]) + \
                buffertext \
                for cidx, e in enumerate(line)
            ) + '|'
        )
        if headers or data_has_header:
            if ridx == 0:
                tablerows.append(
                    '|' + '|'.join(
                        [headersep * (col_widths[cidx] + 2 * bufferlen) \
                        for cidx in range(num_cols)]
                    ) + '|'
                )

    tabletext = '\n'.join(tablerows)

    if showtable:
        print(tabletext)

    return tabletext
Related