Home > Mobile >  How to print two aligned columns of text from a list (which may have an odd number of elements) in p
How to print two aligned columns of text from a list (which may have an odd number of elements) in p

Time:11-10

I have some code which takes input from the user and stores it in a list. The list may have an odd or even number of elements, for example: my_list = ['Beef','Chicken','Eggs','Lamb','Nuts','Pork'] (even number of elements)

or my_list = ['Beef','Chicken','Eggs','Lamb','Nuts','Pork','Potatoes'] (odd number of elements)

I want to store my_list in a string variable, such so that when I print(var) or create a tkinter messagebox, my program will output two columns like this:

-- Beef       --Chicken
-- Eggs       --Lamb
-- Nuts       --Pork
-- Potatoes

I know how to manipulate the strings, but I'm stuck on creating the columns. I have tried this:

for x,y in zip(my_list[0::2], my_list[1::2]):
    print("{0} {1}".format(x, y))

But that doesn't work for lists of odd-number length. I have also tried the more complicated:

#When my_list = ['Beef','Chicken','Eggs','Lamb','Nuts','Pork','Potatoes']
list1 = []
list2 = []
while len(my_list) != 0:
        list1.append(my_list[0])
        my_list.pop(0)
        if len(my_list) == 0:
            list2.append('')
        else:
            list2.append(my_list[0])
            my_list.pop(0)
    for i in range (len(list1)):
        blank_space = 40 - len(list1[i-1])
        string2 = "\n--"   list1[i]   ' '*blank_space   '--'   list2[i]
        string1 = string1   string2
    print(string1)

but the output I get is like this:

--Beef                                --Chicken
--Eggs                                    --Lamb
--Nuts                                    --Pork
--Potatoes                                    --

which doesn't align the columns correctly.

Besides splitting it into columns, it is also important that the output is in the form:

--Element1    --Element2
--Element3    --Element4

and not in any other form. I'd really appreciate any help on where I'm making my mistake. If you need anymore clarification just tell me and I will add it into my question.

CodePudding user response:

How about something like the following, which uses the fact that out-of-range slicing does not throw an error:

my_list = ['Beef','Chicken','Eggs','Lamb','Nuts','Pork','Potatoes']

for i in range(0, len(my_list), 2):
    print(' '.join(f"-- {s:10}" for s in my_list[i:i 2]))

Output:

-- Beef       -- Chicken
-- Eggs       -- Lamb
-- Nuts       -- Pork
-- Potatoes

Or if you want to get a single string, you can nest join:

output = '\n'.join(' '.join(f"-- {s:10}" for s in my_list[i:i 2]) for i in range(0, len(my_list), 2))

CodePudding user response:

Here ya go :-)

Variable columns, validates the longest word fits and should be pretty efficient

# Figure out the number of columns you wish to have in your table.
COLUMNS = 2

my_list = ['Beef','Chicken','Eggs','Lamb','Nuts','Pork','Potatoes']

# Figure our the length of the longest word in the list
longest_word_length = max(map(len,my_list))

# Create a format string that will add some spacing to the list
format_string = f'-- {{0:{longest_word_length 2}}}'

output = []

# Format all the items in the list
for index, item in enumerate(my_list, start=1):
    output.append(format_string.format(item))
    if index % COLUMNS == 0:
        output.append('\n')

print(''.join(output))

You may as well use tabulate with the "plain" format for an easy way to do it.

CodePudding user response:

I tried to put it in a comment but it was too long so it became its own answer. To expand on the other answers, I thought it was a good idea to explain what the code is doing.

Breaking up the code into parts, and starting with j1-lee's answer, we have:

for i in range(0, len(my_list), 2):
    print(' '.join(f"-- {s:10}" for s in my_list[i:i 2]))

or

output = '\n'.join(' '.join(f"-- {s:10}" for s in my_list[i:i 2]) for i in range(0, len(my_list), 2))

There are several parts:

  • f-strings are a handy way of formatting strings. The f before the quotes indicates an f-string.
  • Within the f-string there is a variable s that is part of the list comprehension for s in my_list[i:i 2]. {s:10} indicates that the length of the string is 10. (Or you could do something like what Bharel did and have another variable related to the length of the longest string and use that instead of 10.) This is probably a good idea if you plan to apply it to different lists.
  • (f"-- {s:10}" for s in my_list[i:i 2]) creates a generator, for example if you wrote x = (f"-- {s:10}" for s in my_list[0:0 2]) and then tried for i in x: print(i) your output would be two strings: -- Beef and -- Chicken.
  • the ' '.join(...) joins them together in a list, and like j1-lee says, if you nest them with multiple list comprehensions, you can get a single line.

I think you can probably get the most versatile by combining what j1-lee and Bharel did together. Note that I removed the space in the join command since there is now a variable that defines the space between the columns.

def generate_columns(list_in, n_columns, column_space, output_as_list = True):
    # Figure our the length of the longest word in the list
    longest_word_length = max(map(len,list_in))
    column_length = longest_word_length   column_space

    output = [''.join([f"-- {s:{column_length}}" \
                       for s in my_list[i:i n_columns]]) for i in range(0, len(my_list), n_columns)]
    if output_as_list:
        return output
    return '\n'.join(o for o in output)


my_list = ['Beef','Chicken','Eggs','Lamb','Nuts','Pork','Potatoes']

print(generate_columns(my_list, 3, 5))
#['-- Beef         -- Chicken      -- Eggs         ', '-- Lamb         -- Nuts      -- Pork         ', '-- Potatoes     ']
print(generate_columns(my_list, 2, 3, output_as_list = False))
#-- Beef       -- Chicken
#-- Eggs       -- Lamb
#-- Nuts       -- Pork
#-- Potatoes
  • Related