I have a list of varying length where items is strings of varying length. I want to print them by (a mirrored N)/order by column.
Major points being:
- Columns shall have fixed width == widest data in that column.
- It shall be as compact as possible.
- Number of columns is varying/induced by available width of canvas.
- Order of items should not be rearranged.
- (Item lists printed column wise on a horizontal order disgusts me.)
Optionally:
- Distribution should optionally favour either lower left or upper right.
I currently use this in terminal by bash, C etc. but other uses is not hard to imagine.
Result of calculations should be:
- columns
- lines
- width of each column
As, by this, one can fairly easy print the data in a fixed with column table.
Main question: Is there is some nifty way to do this. (I'm inspired by Knuth's Computer musings.)
My current approach is rather straight forward. Hard to specify the question without some gory details so here we go:
Data Examples
E.g. (by index of string array):
0 4 8 12 or 0 4 8 12 or 0 3 6 9 12 15
1 5 9 13 1 5 9 13 1 4 7 10 13
2 6 10 14 2 6 10 2 5 8 11 14
3 7 11 15 3 7 11
favouring lower left favouring upper right
0 4 8 12 0 4 8 11
1 5 9 13 1 5 9 12
2 6 10 2 6 10 13
3 7 11 3 7
E.g. (by data - actual output):
0) Item number 00000 4) Item Number 04 8) Item Number 008 12) Item Number 00012
1) Item Number 00001 5) Item Number 5 9) Item Number 00009 13) Item Number 0013
2) Item Number 02 6) Item Number 00000006 10) Item Number 10
3) Item Number 003 7) Item Number 7 11) Item Number 11
Current implementation
As of now I do this by (approximately) e.g. in bash:
- Adding the length of each item to array
lens
and tracklongest
item. - Add width for number + 1 for
)
+ 1 forspace
tolongest
item. - Calculate maximum columns given that width.
- Re-calculating width of item number (The one before
')'
in the print.) for each column. - Calculating actual longest width for items in each column.
Re-calculating:
while `lines` > 1 ; do * Available width = Canvas width - total print width * Test: Find longest item in last column as if columns was increased by 1. * If longest_in_last_column_test < available width increase columns by 1. recalculate all column widths. Else break End If done
Print list.
Thoughts
Cant' help but wonder if there is some way to calculate this by other means. E.g. by using matrix mathematics, - or perhaps some nice algorithm out there.
Perhaps hard in bash, but in C by pointers to structs or object related languages.
Exempli gratia:
struct item {
int len;
char *val;
}
struct item items = {{5, "Hello"}, {3, "You"}, ...}
Which would give a matrix of typically
# index:length
0:5 1:2 2:1 3:3 4:5
5:2 6:6 7:9 8:1 9:6
Then by having the restraint of sum of each row being <= available width, e.g. 25, rearrange matrix.
longest: 5 5 9 6 => sum 25
--------------------------
5 3 6 1 => sum 15
5 5 9 6 => sum 25
1 2 1 => sum 4