1

I'm editing this post because I didn't do a good job explaining my question, so here goes again. I'm working with the tabulate library. I'm looking to use input() to automatically adjust the number of columns/rows in a table based off the input given. Here's a basic example:

#!/bin/python3
from tabulate import tabulate
uid1 = input('UID > ')
uid2 = input('UID > ')
name1 = input('NAME > ')
name2 = input('NAME > ')
number1 = input('NUMBER > ')
number2 = input('NUMBER > ')
headers = ["UID", "NAME","NUMBER"]
table = [[uid1,name1,number1],[uid2,name2,number2]]
print(tabulate(table, headers, tablefmt="fancy_grid"))
╒═══════╤═════════╤══════════╕
│   UID │ NAME    │ NUMBER   │
╞═══════╪═════════╪══════════╡
│     0 │ SHAWN   │ 333-4444 │
├───────┼─────────┼──────────┤
│     1 │ MICHAEL │ 222-3333 │
╘═══════╧═════════╧══════════╛

But the next time the script runs, there are more columns/tables:

╒═══════╤════════╤══════════╕
│   UID │ NAME   │ NUMBER   │
╞═══════╪════════╪══════════╡
│     0 │ JAMES  │ 444-5555 │
├───────┼────────┼──────────┤
│     1 │ ANDREW │ 666-3333 │
├───────┼────────┼──────────┤
│     2 │ SHAWN  │ 444-3333 │
╘═══════╧════════╧══════════╛

So I'm trying to figure out a way to adjust the given values for rows and columns with a for loop or something but I can't figure it out. I'd like to have something like:

UIDs = input('Enter all UIDs $ ')
NAMES = input('Enter all names $ ')
NUMBERS = int(input('Enter all numbers $')
WaXxX333
  • 388
  • 1
  • 2
  • 11
  • Why are you using string formatting at all? `split()` gives you a list of strings, and then you're using string formatting to build an identical list of strings for some reason. – user2357112 Jul 16 '21 at 02:08
  • If you are asking if there is a way to iterate over variables, then I would recommend you elaborate more on what you are hoping to achieve. It is possible to do this, but it is a major anti-pattern and most likely not what you want to do. – zr0gravity7 Jul 16 '21 at 02:40
  • I'm not sure why I'm having such a difficult time explaining. So instead of having to put as many values into the ```headers``` and ```table = [[f"{dataone}",f"{datatwo}]]``` , is there any way to automatically add as many values as a user enters ? – WaXxX333 Jul 18 '21 at 03:42
  • With this: ```table = [[f"{dataone}",f"{datatwo}]]```, I would have to do ```dataone = input('dataone: ')``` in order to assign the value. Instead of having to edit it every single time, say for one thing I only need two entries but another I need 4, I would have to edit ```table = [[f"{dataone}",f"{datatwo}]]``` to ```table = [[f"{dataone}",f"{datatwo}",f"{datathree}",f"{datafour}"]]``` and then change it the next time. Can I just do: ```AllData = input('blah>>> ').split()``` and then maybe ```for Data in AllData: make room for values``` – WaXxX333 Jul 18 '21 at 03:45

1 Answers1

1

You could use while and for loops:

CODE

from tabulate import tabulate

def adjust_columns_sizes(columns):
    """
    Adjusts the size of all the
    columns to be the same.
    
    If a column is smaller than
    the biggest, empty strings are added.
    
    Returns a list of lists of strings
    with fixed size.
    
    [['data1', 'data2', 'data3'], <-- column
     ['data']]                    <-- column
    
       ||
       ||
       \/
       
    [['data1', 'data2', 'data3'], <-- column
     ['data', '', '']]            <-- column
    """
    
    columns_sizes = []  # The size of each column
    for column in columns:
        columns_sizes.append(len(column))
    
    # Biggest column size is needed to adjust the
    # smaller columns to the same size.
    biggest_column_size = max(columns_sizes)
    
    # This loop adjust the smaller columns
    fixed_size_columns = []
    for i_column, column in enumerate(columns):  # Enumerate to get the index
        column_length = columns_sizes[i_column]
        if column_length < biggest_column_size:
            
            # Difference of lengths to know how many blank strings
            # to add.
            diff = biggest_column_size - len(column)
            
            # Using list comprehension, and adding of list, the blank
            # strings get added.
            column_with_new_size = column + ['' for _ in range(diff)]
            
            fixed_size_columns.append(column_with_new_size)
        else:
            # If column size is the same as the biggest, just add
            # to the list
            fixed_size_columns.append(column)

    return fixed_size_columns
        
    

def get_headers():
    """
    This function asks for all the headers
    that will be in the table.
    
    Returns a list of strings
    
    ['header', ...]
    """
    
    print('--HEADERS--')
    headers = []  # Headers stored in a list
    while True:
        new_h = input('New header value: ')
        if new_h == '':  # When no value is provided, while loop ends
            break
        headers.append(new_h)

    return headers


def get_body(headers):
    """
    This function asks for the data that will
    be in each column. 
    
    The number of columns is equivalent to the 
    number of headers or the lenght of the list 
    of headers.
    
    Each column will result in a list, but in order to be
    pased as an argument for tabulate, each list
    has to be a row, so we need to transpose
    the columns to rows using the zip function.
    
    Returns a list of tuples of strings. 
    
    [('data', ...), ('data', ...), ...]
    """

    print('--BODY--')
    body = []  # This list will contain the column lists
    for header in headers:
        
        # Message to show for each header
        i_msg = 'Enter all ' + header.lower() + '\'s separated by spaces: '
        
        # getting the data
        data_for_column = input(i_msg)  
        
        # getting a list splitting the data
        column = data_for_column.split()  
        
        body.append(column)
        
    # Adjusting the column sizes in order to zip to work properly
    adjusted_body = adjust_columns_sizes(body)
    
    # Transpose the columns to rows.
    # Using the * operator to pass every column in the list.
    # Using list() because zip returns an iterable object.
    transposed = list(zip(*adjusted_body))
   
    return transposed


if __name__ == '__main__':
    # Getting table headers
    headers = get_headers()
    
    # Getting the data en each column for each header
    # but transposed as rows
    table = get_body(headers)
    
    print(tabulate(table, headers, tablefmt="fancy_grid"))

RESULT

--HEADERS--
New header value: UID
New header value: NAME
New header value: NUMBER
New header value:
--BODY--
Enter all uid's separated by spaces: 0 1 2 3
Enter all name's separated by spaces: SHAWN MICHAEL JAMES ANDREW
Enter all number's separated by spaces: 333-444 222-333 444-555
╒═══════╤═════════╤══════════╕
│   UID │ NAME    │ NUMBER   │
╞═══════╪═════════╪══════════╡
│     0 │ SHAWN   │ 333-444  │
├───────┼─────────┼──────────┤
│     1 │ MICHAEL │ 222-333  │
├───────┼─────────┼──────────┤
│     2 │ JAMES   │ 444-555  │
├───────┼─────────┼──────────┤
│     3 │ ANDREW  │          │
╘═══════╧═════════╧══════════╛
Kyostenas
  • 27
  • 4