Pretty Print 2D List

Pretty print 2D list?

To make things interesting, let's try with a bigger matrix:

matrix = [
["Ah!", "We do have some Camembert", "sir"],
["It's a bit", "runny", "sir"],
["Well,", "as a matter of fact it's", "very runny, sir"],
["I think it's runnier", "than you", "like it, sir"]
]

s = [[str(e) for e in row] for row in matrix]
lens = [max(map(len, col)) for col in zip(*s)]
fmt = '\t'.join('{{:{}}}'.format(x) for x in lens)
table = [fmt.format(*row) for row in s]
print '\n'.join(table)

Output:

Ah!                     We do have some Camembert   sir            
It's a bit runny sir
Well, as a matter of fact it's very runny, sir
I think it's runnier than you like it, sir

UPD: for multiline cells, something like this should work:

text = [
["Ah!", "We do have\nsome Camembert", "sir"],
["It's a bit", "runny", "sir"],
["Well,", "as a matter\nof fact it's", "very runny,\nsir"],
["I think it's\nrunnier", "than you", "like it,\nsir"]
]

from itertools import chain, izip_longest

matrix = chain.from_iterable(
izip_longest(
*(x.splitlines() for x in y),
fillvalue='')
for y in text)

And then apply the above code.

See also http://pypi.python.org/pypi/texttable

Print 2D list with each number right justified

The current code adds a newline from the print call for every cell, causing every element to appear on its own line. You can pass the named parameter end="" into print, then manually add newlines after printing each row:

def print_square(square):
for line in square:
for i in line:
print(str(i).rjust(10), end="")

print()

if __name__ == "__main__":
print_square([[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12]])

Or you can use * to unpack the list as in the next example and optionally use the sep named parameter. It's also nice to parameterize the pad amount and give it a default value, increasing reusability.

def print_square(square, pad=10):
for line in square:
print(*[str(i).rjust(pad) for i in line], sep=" ")

Or you can use join:

def print_square(square, pad=10):
for line in square:
print(" ".join(str(x).rjust(pad) for x in line))

Alternately, you can dynamically determine the padding based on the longest element:

def print_square(square):
pad = max(len(str(x)) for y in square for x in y)

for line in square:
print(" ".join(str(x).rjust(pad) for x in line))

pretty print 2d matrix and call a sorting function at the same time

Your problem is with the sorting function, the pretty print is working correctly. Here is one way to do the first, without re-inventing the wheel, using native python functions.

First you need to convert L from being a 2D array into a dictionary of the following format.

L2 = {'kevin': [8.5, 17.1, 5.9, 15.0, 18], 'arsene': [7.1, 4.4, 15.0, 5.6, 18] }

This will make it easier to access the name which we are interested in and then we sort alphabetically by using sorted(list(L2)).

To convert to a dictionary of the above format you can simply do

L2: dict = {}

for item in L: # In pseudo-code L2[name] = nums
L2[item[0]] = [i for i in item[1:len(item)]] # item[0] is name and 1:len(item) the rest of the data (the numbers)

Then we can short L2, by converting it to a list, and then looping throught the sorted list and recreating the first L list of lists in order now.

L = [] # Set this to empty because we are re-transfering the data
SORTED_L2 = sorted(list(L2)) # sort the list of L2 (only the names)
for name in SORTED_L2:
numbers = L2[name]
L.append([name, *numbers]) # * is for unpacking

And then finally by calling print('\n'.join(['\t'.join([str(cell) for cell in row]) for row in L])) you can pretty print them. The output

anna    9.7     12.8    10.6    6.9     20
arsene 7.1 4.4 15.0 5.6 18
aurelie 3.6 18.8 8.2 18.2 18
kevin 8.5 17.1 5.9 15.0 18
lubin 16.3 14.8 13.1 5.6 20
luna 14.6 11.5 15.2 18.5 19
shadene 17.9 7.1 16.7 2.5 19
sophie 7.4 2.1 18.1 2.9 19
toufik 1.1 2.2 13.4 3.1 20
yannis 18.8 2.4 12.0 8.0 18

You can now wrap it all in one function like follows

def sortL(L):
# Convert to dictionary for easy access
L2: dict = {}
for item in L:
L2[item[0]] = [i for i in item[1:len(item)]]

SORTED_L2 = sorted(list(L2)) # Sort the names
L = []
for item in SORTED_L2:
L.append([item, *L2[item]])
return L

def SortAndPrettyPrint(L):
L = sortL(L)
print('\n'.join(['\t'.join([str(cell) for cell in row]) for row in L]))

Pretty Printing (2D Arrays, Box)

Your problem was that len(listOfLists) was used for the size of the printed table in both directions. len(listOfLists) defaults to number of rows, by doing len(listOfLists[0]) you get the number of columns.

 listOfLists = [['a', 'b', 'c'],
['d', 'e', 'f'],
['g', 'h', 'i'],
['j', 'k', 'l']]

for row in range(len(listOfLists)):
print('+' + '-+'*len(listOfLists[0]))
print('|', end='')
for col in range(len(listOfLists[row])):
print(listOfLists[row][col], end='|')
print(' ') #To change lines
print('+' + '-+'*(len(listOfLists[0])))

output:

+-+-+-+
|a|b|c|
+-+-+-+
|d|e|f|
+-+-+-+
|g|h|i|
+-+-+-+
|j|k|l|
+-+-+-+

Happy coding!

Pretty-Printing 2D List in Haskell (Explanation of Failure)

In your case the type should be ppW :: W -> IO (). () (pronounced "unit") is a type which can have only one* value - namely (). So IO () is an IO action which as a result gives no value (It is equivalence of void functions from C, C++ or Java).

Here is some piece of code that should compile:

data X = Y | Z
deriving (Eq, Show)

type R = [X]

type W = [R]

ppR :: R -> IO ()
ppR = putStrLn . show

ppW :: W -> IO ()
ppW (w:[]) = ppR w
ppW (w:ws) = ppR w >> ppW ws

If you have any problem with types you can always use ghci to determine type of any function. Or you can simply look at the types of functions you are using:

putStrLn :: String -> IO()
(>>) :: IO a -> IO b -> IO b -- this is not exactly what ghci would tell you.

Edit:
In the code I included I used type instead of data. type defines a type synonym (it is like C/C++ typedef). It is easier to use them than to use data - data requires you to write explicitly the name of constructor, so you would have:

data R =  R [X]

ppR :: R -> IO ()
ppR (R r)= putStrLn (show r)

*actually it can also be also bottom, but that's a different story.

Pretty print 2D array in Java

If you want something similar to MySQL command-line client output, you can use something like that:

import java.io.PrintStream;

import static java.lang.String.format;
import static java.lang.System.out;

public final class PrettyPrinter {

private static final char BORDER_KNOT = '+';
private static final char HORIZONTAL_BORDER = '-';
private static final char VERTICAL_BORDER = '|';

private static final String DEFAULT_AS_NULL = "(NULL)";

private final PrintStream out;
private final String asNull;

public PrettyPrinter(PrintStream out) {
this(out, DEFAULT_AS_NULL);
}

public PrettyPrinter(PrintStream out, String asNull) {
if ( out == null ) {
throw new IllegalArgumentException("No print stream provided");
}
if ( asNull == null ) {
throw new IllegalArgumentException("No NULL-value placeholder provided");
}
this.out = out;
this.asNull = asNull;
}

public void print(String[][] table) {
if ( table == null ) {
throw new IllegalArgumentException("No tabular data provided");
}
if ( table.length == 0 ) {
return;
}
final int[] widths = new int[getMaxColumns(table)];
adjustColumnWidths(table, widths);
printPreparedTable(table, widths, getHorizontalBorder(widths));
}

private void printPreparedTable(String[][] table, int widths[], String horizontalBorder) {
final int lineLength = horizontalBorder.length();
out.println(horizontalBorder);
for ( final String[] row : table ) {
if ( row != null ) {
out.println(getRow(row, widths, lineLength));
out.println(horizontalBorder);
}
}
}

private String getRow(String[] row, int[] widths, int lineLength) {
final StringBuilder builder = new StringBuilder(lineLength).append(VERTICAL_BORDER);
final int maxWidths = widths.length;
for ( int i = 0; i < maxWidths; i++ ) {
builder.append(padRight(getCellValue(safeGet(row, i, null)), widths[i])).append(VERTICAL_BORDER);
}
return builder.toString();
}

private String getHorizontalBorder(int[] widths) {
final StringBuilder builder = new StringBuilder(256);
builder.append(BORDER_KNOT);
for ( final int w : widths ) {
for ( int i = 0; i < w; i++ ) {
builder.append(HORIZONTAL_BORDER);
}
builder.append(BORDER_KNOT);
}
return builder.toString();
}

private int getMaxColumns(String[][] rows) {
int max = 0;
for ( final String[] row : rows ) {
if ( row != null && row.length > max ) {
max = row.length;
}
}
return max;
}

private void adjustColumnWidths(String[][] rows, int[] widths) {
for ( final String[] row : rows ) {
if ( row != null ) {
for ( int c = 0; c < widths.length; c++ ) {
final String cv = getCellValue(safeGet(row, c, asNull));
final int l = cv.length();
if ( widths[c] < l ) {
widths[c] = l;
}
}
}
}
}

private static String padRight(String s, int n) {
return format("%1$-" + n + "s", s);
}

private static String safeGet(String[] array, int index, String defaultValue) {
return index < array.length ? array[index] : defaultValue;
}

private String getCellValue(Object value) {
return value == null ? asNull : value.toString();
}

}

And use it like that:

final PrettyPrinter printer = new PrettyPrinter(out);
printer.print(new String[][] {
new String[] {"FIRST NAME", "LAST NAME", "DATE OF BIRTH", "NOTES"},
new String[] {"Joe", "Smith", "November 2, 1972"},
null,
new String[] {"John", "Doe", "April 29, 1970", "Big Brother"},
new String[] {"Jack", null, null, "(yes, no last name)"},
});

The code above will produce the following output:

+----------+---------+----------------+-------------------+
|FIRST NAME|LAST NAME|DATE OF BIRTH |NOTES |
+----------+---------+----------------+-------------------+
|Joe |Smith |November 2, 1972|(NULL) |
+----------+---------+----------------+-------------------+
|John |Doe |April 29, 1970 |Big Brother |
+----------+---------+----------------+-------------------+
|Jack |(NULL) |(NULL) |(yes, no last name)|
+----------+---------+----------------+-------------------+

Printing out a 2D list like a table with Python

As others have commented, there are a lot of concepts going on here (too many to be manageable in a single answer). But for your further study (try out each statement in turn with a (small) example 2D list), here's how it breaks down:

Turn the data into a list of lists of strings (uses list comprehension):

s = [[str(e) for e in row] for row in matrix]

Get a list of the maximum number of characters in each column so we know how to format the columns:

lens = [max(map(len, col)) for col in zip(*s)]

(This one is more complex: zip() here enables us to iterate over the columns of s, passing each to the len() method to find its length (this is achieved with map()); then find the maximum length of each column with the max() builtin.)

Set up the corresponding Python format strings as tab-separated entries:

fmt = '\t'.join('{{:{}}}'.format(x) for x in lens)

fmt is now the format specifier for every row, e.g. '{:4}\t{:6}\t{:6}' for three columns with widths 4,6,6 (NB only works on Python 2.7+ because the fields haven't been numbered)

Set up the table as a list of rows in their string format (use another list comprehension):

table = [fmt.format(*row) for row in s]

Join the whole lot together in a single string, with rows separated by newlines:

print '\n'.join(table)

join() takes a list of strings and produces one string with them all joined together by the chosen delimiter (here, \n, the newline character).



Related Topics



Leave a reply



Submit