Skip navigation links
Ascii Table: 0.2.3

Package de.vandermeer.asciitable.commons

Common artifacts for the ASCII tables.

See: Description

Package de.vandermeer.asciitable.commons Description

Common artifacts for the ASCII tables.

Array Transformations

Collections of utility methods to manipulate (transform) arrays. They solve a number of common problems when using multi-dimensional arrays (as the table implementations do for rendering, here 2-dimensional arrays):

The Problem

Let's call a row a line in a table. A table can have multiple (basically any number of ) rows. Let's call a column a part of a row with special formatting. A row can have one or more columns, with each row of a the same table having the same number of columns. Let's call a cell a part of the table identified by row and column. For instance the 2nd column of the 3rd row would be cell 3-2.

Filling a table with content means to add rows with their columns, one row at a time until all rows are added. The tables here provide and addRow() method with variable argument, checking per table that the number of columns (objects in the argument) is equal per row added. If all cells fit in the defined (or calculated) width of the columns and tables, nothing special is required. Here, one can use lists or sets or arrays to represent the rows with their columns and easily render them. For instance, the following code creates a table with all cells fitting in the calculated width (2 rows with 3 columns each and width of 19):

	V2_AsciiTable at = new V2_AsciiTable();
	at.addRule();
	at.addRow("1-1", "1-2", "1-3");
	at.addRule();
	at.addRow("2-1", "2-2", "2-3");
	at.addRule();
 
With the rendered output of (using a renderer with the V2_E_TableThemes.UTF_LIGHT theme):
        ┌─────┬─────┬─────┐
        │ 1-1 │ 1-2 │ 1-3 │
        ├─────┼─────┼─────┤
        │ 2-1 │ 2-2 │ 2-3 │
        └─────┴─────┴─────┘
 
However, if only one of the cells is "over-width" this simple approach will not work anymore. For instance using the following code for the first row will create a problem:

	at.addRow("1-1", "1-2 text", "1-3");
 
The expected rendered table would need to wrap the over size cell 1-2 resulting in the following output:
        ┌─────┬─────┬─────┐
        │ 1-1 │ 1-2 │ 1-3 │
        │     │ tex │     │
        │     │ t   │     │
        ├─────┼─────┼─────┤
        │ 2-1 │ 2-2 │ 2-3 │
        └─────┴─────┴─────┘
 
This means to actually add (for the render process), multiple lines to cells 1-1 and 1-3 to match up with the new added lines in cell 2-2. Simply using lists or sets or even arrays may (can) result in complicated code. The approach taken in the ASCII table is to ignore this problem until a table is to be rendered. Then the methods introduced above come in handy to calculate a 2-dimensional array solving the problem described here (and a few more).

The Solution - Wrap and Normalize

A table is filled as described above: row by row with each row having columns and the content of each column set by an object. When filling a table, nothing is done beside creating an array of objects as columns per row added to the table.

A renderer then sees a table as a set of rows, each of which is an array of objects. The objects are the content of cells, their respective toString() method being used to create the content. The renderer also has the width of columns and the overall table width.

Per row, the renderer then creates a 2-dimensional array. In the simple case that all cells fit in the given width, this array will have a width of 3 (3 columns per row) and a length of 1 (nothing done with the cell content) per row.

In the simple case (all cells fit) described above, the renderer will simply create the following content arrays for row 1 (top) and row 2 (bottom):
        [0][0]: 1-1
        [1][0]: 1-2
        [2][0]: 1-3

        [0][0]: 2-1
        [1][0]: 2-2
        [2][0]: 2-3

 

For the second example above, with an over-size column, the renderer will need to first wrap the contents of cell 1-2 and then normalize the content array of row 1 adding the new lines in cell 1-1 and cell 1-3 to match the new created lines for the wrapped lines in cell 1-2.

To do that, the renderer uses the two array transformation methods ArrayTransformations.WRAP_LINES(int, Object) to wrap the lines in cell 1-2 and ArrayTransformations.NORMALISE_ARRAY(int, String[][]) to normalize the cells 1-1 and 1-3.

The content arrays for row 1 and 2 look then as shown below. Row 1 has added lines for cell 1-1 and 1-3 and wrapped lines for cell 1-2 (the content of 0 in those added lines means empty line). Row 2 is the same as for the simple example.
        [0][0]: 1-1
        [0][1]: 0
        [0][2]: 0
        [1][0]: 1-2
        [1][1]: tex
        [1][2]: t
        [2][0]: 1-3
        [2][1]: 0
        [2][2]: 0

        [0][0]: 2-1
        [1][0]: 2-2
        [2][0]: 2-3
 

The Solution - Flip

Once the renderer has created a content array per row with wrapped lines and normalized cells, the next problem is to create the actual output. As can be seen in the last example above (wrapped lines for cell 1-2), using the originally created array is not very efficient, because the renderer will need complicated nested loops to reach all cells.

However, if we flip the content array (do a horizontal and vertical transformation), we will get a content array that has per first dimension all cells to be printed. This is what ArrayTransformations.FLIP_ARRAY(String[][]) does.

For the simple example above, created content array looked like this:
        [0][0]: 1-1
        [1][0]: 1-2
        [2][0]: 1-3

        [0][0]: 2-1
        [1][0]: 2-2
        [2][0]: 2-3
 
Flipping these arrays will result in the following:
        [0][0]: 1-1
        [0][1]: 1-2
        [0][2]: 1-3

        [0][0]: 2-1
        [0][1]: 2-2
        [0][2]: 2-3
 

Now, it is a simple loop throw the arrays first dimension for all printable lines, and a simple loop through the arrays second dimension for all printable cells.

Similar for the over-size example above. The original content arrays looked like this:
        [0][0]: 1-1
        [0][1]: 0
        [0][2]: 0
        [1][0]: 1-2
        [1][1]: tex
        [1][2]: t
        [2][0]: 1-3
        [2][1]: 0
        [2][2]: 0

        [0][0]: 2-1
        [1][0]: 2-2
        [2][0]: 2-3
 
Fliping the arrays will result in the following arrays for the renderer:
        [0][0]: 1-1
        [0][1]: 1-2
        [0][2]: 1-3
        [1][0]: 0
        [1][1]: tex
        [1][2]: 0
        [2][0]: 0
        [2][1]: t
        [2][2]: 0

        [0][0]: 2-1
        [0][1]: 2-2
        [0][2]: 2-3
 

Complete solution - creating a content array

Taking version 2 and the over-size example above, a complete solution is implemented in RenderUtilities.createContentArray(Object[], int[], int[]). The method receives the original content array of a row plus an integer array with column width and an integer array with padding per column (V2 introduced padding for columns). The following code shows how a renderer would call this method:

	String[][] ar;
	ar = V2_Utilities.createContentArray(new Object[]{"1-1", "1-2 text", "1-3"}, new int[]{5, 5, 5}, new int[]{1, 1, 1});
 
The method then creates a return array:

	String[][] ret = new String[width.length][];
 
Per entry in the given content array, it then determines if lines have to be wrapped (content of null means column span):

	int length = 0;
	for(int i=0; i<columns.length; i++){
		Object o = columns[i];
		if(o==null){
			length += width[i];
			continue;
		}
		else{
			length += width[i];
		}
		if(padding[i]>0){
			length = length - padding[i]*2;
		}
		ret[i] = ArrayTransformations.WRAP_LINES(length, o);
		length = 0;
	}
 
Once the line wrapping is done, the resulting array can be normalized:

	ret = ArrayTransformations.NORMALISE_ARRAY(width.length, ret);
 
And then finally flipped and returned:

	ret = ArrayTransformations.FLIP_ARRAY(ret);
	return ret;
 

A ToString Style

A style definition helping to simplify toString() methods using StandardToStringStyle.

A Table Exception

TableException implements a runtime exception. This is used in the tables for instance for initialization substituting for more common runtime or illegal argument exceptions.
Version:
v0.2.3 build 150910 (10-Sep-15) for Java 1.7
Author:
Sven van der Meer <vdmeer.sven@mykolab.com>
Skip navigation links
Ascii Table: 0.2.3

Copyright © 2010–2015. All rights reserved.