-1

I have a list of lists like:

a = [[1, 10, 0.1], [2, 10, 0.2], [3, 11, 0.25]]

For each list (a list of 3 fields), I want to separate the fields into separate variables and print with appropriate formatting, with column names, dollar signs, clean spacing, nicely lined up, etc. for example:

ID Amount Rate
1  $ 10   0.1
2  $ 10   0.2
3  $ 11   0.25

I tried using zip() but what was printed out won't work if I want to sort the price or amount. I'd be very grateful if anyone could help me with my question only using the built-in functions in Python.

colidyre
  • 4,170
  • 12
  • 37
  • 53
Chloe
  • 11
  • Does this answer your question? [Printing Lists as Tabular Data](https://stackoverflow.com/questions/9535954/printing-lists-as-tabular-data) – sahasrara62 Aug 02 '22 at 22:25
  • 1
    On this site you need to show what you’ve tried and ask targeted questions. This is likely to get closed as it stands. – bob Aug 02 '22 at 22:30
  • agreed, I would really like to see an [attempt](https://idownvotedbecau.se/noattempt). like any kind of one really. – rv.kvetch Aug 02 '22 at 22:37
  • possible [duplicate](https://stackoverflow.com/questions/72890904/how-to-align-strings-in-columns/72891689#72891689) – cards Aug 03 '22 at 00:48

4 Answers4

2

There are lots of formatted output options in Python. Just pick one.

a = [[1, 10, 0.1], [2, 10, 0.2], [3, 11, 0.25]]

print( " ID  Amount  Rate")
for row in a:
    print( f"{row[0]:3d}   ${row[1]:3d}   {row[2]:4.2f}" )
for row in a:
    print( "{:3d}   ${:3d}   {:4.2f}".format(*row) )

Output:

 ID  Amount  Rate
  1   $ 10   0.10
  2   $ 10   0.20
  3   $ 11   0.25
  1   $ 10   0.10
  2   $ 10   0.20
  3   $ 11   0.25
Tim Roberts
  • 48,973
  • 4
  • 21
  • 30
  • 1
    the size of the columns are hardcoded. if a value in a list would be like `10000` then the whole layout is messed-up – cards Aug 03 '22 at 00:43
1

not a built-in function but have you tried using pandas? takes care of allot of of that for you try:

from pandas import DataFrame

normal_list = [[1, 10, 0.1], [2, 10, 0.2], [3, 11, 0.25]]

prettier_dataframe = DataFrame([[1, 10, 0.1], [2, 10, 0.2], [3, 11, 0.25]], columns = ["col1", "col2", "col3"], index = ["row1", "row2", "row3"])

print(prettier_dataframe)

Output:

      col1  col2  col3
row1     1    10  0.10
row2     2    10  0.20
row3     3    11  0.25
Joooeey
  • 3,394
  • 1
  • 35
  • 49
1

If you want to outsource the formatting to have a clean usage like this or similar

for data in your_seq:
    print(data)

then you can consider using a class and design the output there. The advantage is a separation of formatting the data and the data itself. Here is one example with equal distributed length for each column using dataclass:

from dataclasses import dataclass


@dataclass
class Data:
    ID: int
    Amount: int
    Rate: float

    @property
    def column_length(self):
        return self.get_longest_column_length()

    @classmethod
    def get_longest_column_length(cls):
        return len(max(cls.__annotations__, key=len)) + 1

    @classmethod
    def print_headline(cls):
        length = cls.get_longest_column_length()
        for var in cls.__annotations__:
            print(f"{var:<{length}}", sep="", end="")
        print()

    def __repr__(self):
        return (
            f"{self.ID:<{self.column_length}}"
            f"$ {self.Amount:<{self.column_length - 2}}"
            f"{self.Rate:<{self.column_length}}"
        )

For the usage, you can directly create Data instances or transform the items of an existing list to Data instances like this:

a = [[1, 10, 0.1], [2, 10, 0.2], [3, 11, 0.25]]
data = (Data(*el) for el in a)

Then you can do what I mentioned for the first code snippet:

Data.print_headline()
for date in data:
    print(date)

There is maybe space for optimization here and there. And the low-level detail how to probably format your code is only moved away to the __repr__ method. So regarding this, there is not really something new in comparison to other answers. But you also mentioned

appropriate formatting, with column names, dollar signs, clean spacing, nicely lined up, etc.

, so I had the feeling that using a class could be helpful as a potential starting point for more sophisticated formatting problems and trying to go a bit into the direction of separation of concerns (formatting vs. data).

The output for your provided data is:

ID     Amount Rate   
1      $ 10   0.1    
2      $ 10   0.2    
3      $ 11   0.25   
colidyre
  • 4,170
  • 12
  • 37
  • 53
  • 1
    noice. the `map` usage probably could be replaced with something like `data = (Data(*el) for el in a)` too. maybe a bit more efficient than `map` too, haven't tested though. – rv.kvetch Aug 03 '22 at 16:44
  • 1
    also, `*vars(cls)["__annotations__"]` looks like can be replaced by `cls.__annotations__`. Similarly, for loop can be simplified to `for var in cls.__annotations__:`. Apart from caching value of `column_length` with something like `@cached_property`, I don't see a whole lot of other optimizations honestly. – rv.kvetch Aug 03 '22 at 16:49
  • 1
    Thanks @rv.kvetch. I've applied your helpful suggestions. – colidyre Aug 03 '22 at 17:14
  • 1
    one other thought is the `.keys()` might be a bit redundant when iterating over a dict (since I believe it is default behavior in any case) but again it comes down to preference and as well it's good for clarity purposes I suppose. – rv.kvetch Aug 03 '22 at 17:23
  • 1
    Yes, you're right. It is not necessary. I prefer deleting this as well. Explicit is better than implicit, but too explicit is maybe also not good. My assumption is here, that this is common knowledge. So thanks again for this! – colidyre Aug 03 '22 at 17:32
-2

okay, built-in functions only

a = [[1, 10, 0.1], [2, 10, 0.2], [3, 11, 0.25]]
col_names = ["col1", "col2", "col3"]
row_names = ["row1", "row2", "row3"]

print("       ", *(col +"   " for col in col_names))
for row in range(len(row_names)):
    row_data = (str(a[row][n])+"   "+(" "*(len(col_names[n])-len(str(a[row][n])))) for n in range(len(a[row])))
    print(row_names[row] ,"   ",*row_data)

it messy but heres a rundown,

the first print prints the column names followed by a few spaces fed by a generator of the col_names list (plus a few spaces at the beginning to make room for the row names)

the for loop is to make sure to catch each row

the row_data variable does the same thing as the generator at the beginning, but concatenates the data from list a with enough spaces to make up the difference between the length of the column names and the length of the data (so that the rows and columns line up)

then the second print function just prints that line out with the row name at the beginning