Feature request: print multiple tables, side-by-side
Thanks for this library. I really appreciate how easy it was to quickly understand and apply. Nice job on the docs and API design!
I found myself printing a couple narrow tables, where they could have fit side-by-side in my terminal. Something like this:
Table One Table Two
┌───────┬──────┬──────┐ ┌───────┬──────┬──────┐
│ Foo │ Bar │ Baz │ │ Foo │ Bar │ Baz │
├───────┼──────┼──────┤ ├───────┼──────┼──────┤
│ aaa │ 13 │ 8 │ │ aaa │ 43 │ 8 │
│ bbb │ 99 │ 10 │ │ bbb │ 12 │ 10 │
│ ccc │ 91 │ 9 │ │ ccc │ 12 │ 9 │
│ ddd │ 45 │ 6 │ │ ddd │ 75 │ 6 │
│ eee │ 32 │ 4 │ │ eee │ 62 │ 4 │
│ fff │ 31 │ 4 │ │ fff │ 61 │ 4 │
│ ggg │ 26 │ 3 │ │ ggg │ 56 │ 3 │
│ hhh │ 12 │ 7 │ └───────┴──────┴──────┘
│ iii │ 21 │ 7 │
└───────┴──────┴──────┘
Would you be open to a PR that adds something like this? I'm thinking the API could be something like:
import { printTables } from "console-table-printer";
// ...
printTables(table1,table2);
It would be fun to generalize this to n tables, but for now here's a quick-and-dirty solution for two:
function printTables(table1: Table, table2: Table) {
const t1 = table1.render().split("\n");
const t2 = table2.render().split("\n");
const t1EmptyRow = " ".repeat(t1[1].length);
const together = _.zip(t1, t2).map(
([a, b]) => `${a || t1EmptyRow} ${b || ""}`
);
together.forEach((line) => console.log(line));
}
@jrr thanks for the idea.
It does not seem to be a very Common usecase. If this is preferred by many others I will reconsider. I will keep this Issue open to see how many people prefers this.
@jrr
It would be fun to generalize this to n tables, but for now here's a quick-and-dirty solution for two:
Old Code
const zip = (...args) => {
// https://stackoverflow.com/a/55648257/13077523
const iterators = args.map((arr) => arr[Symbol.iterator]());
let iterateInstances = iterators.map((i) => i.next());
ret = [];
while (iterateInstances["some"]((it) => !it.done)) {
ret.push(iterateInstances.map((it) => it.value));
iterateInstances = iterators.map((i) => i.next());
}
return ret;
};
const printTables = (...tables) => {
const tablesLines = tables.map((table) => table.render().split("\n"));
const emptyRows = tablesLines.map((t) => " ".repeat(t[1].length));
const together = [];
zip(...tablesLines).forEach((row) => {
let out = "";
row.forEach((t, index) => {
out += t || emptyRows[index];
out += " ";
});
together.push(out);
});
together.forEach((line) => console.log(line));
};
There you go!
Honestly you could directly console.log(out) w/o saving to an array, but oh well.
This does not take into account the console size, so it is bound to break on a big number of tables.
New code that considers the terminal's width.
const zip = (...args) => {
// https://stackoverflow.com/a/55648257/13077523
const iterators = args.map((arr) => arr[Symbol.iterator]());
let iterateInstances = iterators.map((i) => i.next());
ret = [];
while (iterateInstances["some"]((it) => !it.done)) {
ret.push(iterateInstances.map((it) => it.value));
iterateInstances = iterators.map((i) => i.next());
}
return ret;
};
const printTables = (...tables) => {
const tablesLines = tables.map((table) => table.render().split("\n"));
const emptyRows = tablesLines.map((t) => " ".repeat(t[1].length));
const together = [];
const groups = [];
if (
emptyRows.reduce((a, b) => a + b).length + emptyRows.length - 2 >
(process.stdout.columns || 80)
) {
let group = [];
let size = emptyRows.length - 1;
let index = 0;
while (emptyRows[index] && size < (process.stdout.columns || 80)) {
if (
size + emptyRows[index].length >
(process.stdout.columns || 80)
) {
size = 0;
groups.push(Array.from(group));
group.length = 0;
} else {
group.push(tablesLines[index]);
size += emptyRows[index].length;
index++;
}
}
if (group.length != 0) {
groups.push(group);
}
} else {
groups.push(tablesLines);
}
for (const group of groups) {
zip(...group).forEach((row) => {
let out = "";
row.forEach((t, index) => {
out += t || emptyRows[index];
out += " ";
});
together.push(out.trim());
});
}
together.forEach((line) => console.log(line));
};
Example output if the console's width is 40 characters long
Table 1 Table 2
┌───────┬─────┐ ┌───────┬─────┐
│ index │ num │ │ index │ num │
├───────┼─────┤ ├───────┼─────┤
│ 0 │ 1 │ │ 0 │ 1 │
│ 1 │ 2 │ │ 1 │ 2 │
│ 0 │ 1 │ │ 0 │ 1 │
│ 1 │ 2 │ │ 1 │ 2 │
└───────┴─────┘ └───────┴─────┘
Example output if the console's width is 20 characters long
Table 1
┌───────┬─────┐
│ index │ num │
├───────┼─────┤
│ 0 │ 1 │
│ 1 │ 2 │
│ 0 │ 1 │
│ 1 │ 2 │
└───────┴─────┘
Table 2
┌───────┬─────┐
│ index │ num │
├───────┼─────┤
│ 0 │ 1 │
│ 1 │ 2 │
│ 0 │ 1 │
│ 1 │ 2 │
└───────┴─────┘
Wow, I wasted 4 hours of my life trying to make it consider the terminal's width.... But at least I did it!
I'll never do shit like this again. 🤣🤣🤣