Tommy Yap Tommy Yap - 22 days ago 5
Java Question

Print table format with dynamic column size

I am not sure how to explain in words. I am trying to achieve this in my cmd after running.

Event Average Stdev Weight
Logins 4.50 1.25 2
Total time online 287.15 42.12 1
Emails sent 65.40 30.71 1
Orders processed 150.73 20.13 1
Pizza's ordered online 2.03 1.06 0.5


But now my result is like this

Event Average Stdev Weight
Logins 3.33 1.25 2.0
Time Online 335.33 33.52 1.0
Emails Sent 66.00 15.51 1.0
Orders processed 150.67 17.25 1.0
Pizza's Ordered 2.33 1.25 0.5


The event name can be long or short, is up to user input. Is it possible to format nicely regardless of the event name length. My value are all correct, is just the formatting. Below is my printing code.

Formatter formatter = new Formatter();
System.out.println(formatter.format("%s %20s %20s %20s", "Event", "Average", "Stdev", "Weight"));
int count = 0;
for (Map.Entry<String, Double> entry : eventsMap.entrySet()) {
formatter = new Formatter();
String event = entry.getKey();
double weight = entry.getValue();
System.out.println(formatter.format("%s %20s %20s %20s", event, average[count], stdev[count], weight));
count++;
}

Answer

The main problem is that you didn't specify the minimum length of the event string, therefore the subsequent contents positions depend on that.

But to avoid problems in the future I would suggest you to use fixed lengths, so if you have a string with length greater than the minimum length, the string gets automatically truncated but the alignments remains correct.

To specify a fixed length you should put both minimum and maximum length with the same value; you can also left align the strings with -.

For example %-20.20s:

- is to left align the string, otherwise it will be right aligned

20 indicates the minimum length

.20 indicates the maximum length, we put it equals to the minimum length to have a fixed length

In your example you need to decide the desired fixed lengths of all the elements you wanna display (also the event string) and then everything should be aligned accordingly.

If you want to be sure that the event string doesn't get truncated you could find its maximum length in your Map and then use that value to create the minimum or fixed length for the formatter:

int eventMaxLength = ... // assign the max length
String eventFormat = "%-" + eventMaxLength + "." + eventMaxLength + "s";
System.out.println(formatter.format(eventFormat + " %-20.20s %-20.20s ...