We're getting markdown tables! I assume this is what they look like:
data
data data data
---------------------
| |
| |
| |
| |
Your task is to make a program or function to generate one of these tables. You'll be given input (string, list of lines, list of characters, etc.) containing data, which looks like this:
datadata
data
data data
data data data
The data consists of spaces and non-overlapping datas. The data will not necessarily form neat stacks (it can float in midair). There is guaranteed to be data on the top and bottom lines, as well as some touching the left side. You can choose if the data is right padded with spaces or not.
The table will always be six characters wider than the data, padded three spaces on the left. The table top is directly below the bottom row of data, and is made up of a line of -s.
As for the legs, everyone knows taller tables can support more weight, so they'll need to be one unit tall for every data in the input. They will be made up of |s, one space in from the sides.
This is code-golf, so shortest answer in bytes per language wins!
Test cases
Input:
data
Output:
data
----------
| |
Input:
data data data
data data data
Output:
data data data
data data data
---------------------
| |
| |
| |
| |
| |
| |
Input:
data
data
Output:
data
data
----------
| |
| |
16 Answers 16
Perl 5 -lpF, (削除) 88 (削除ここまで) (削除) 74 (削除ここまで) 66 bytes
Because we're allowed to require the input to be padded on the right side, @DomHastings was able to shave 8 bytes off my method while eliminating the need for List::Util.
END{printf'-'x(@F+6)."
|%@{[@F+3]}s"x$q,("|")x$q}s// /;$q+=y;d;
-
1\$\begingroup\$ +1. You can save 8 bytes if you have right-padded input and use
-Ftoo! Try it online! \$\endgroup\$Dom Hastings– Dom Hastings2020年12月04日 13:36:27 +00:00Commented Dec 4, 2020 at 13:36
05AB1E, (削除) 31 (削除ここまで) (削除) 30 (削除ここまで) 28 bytes
¬g×ばつa×ばつ'|1®Í‚ǝIJ'd¢и«.c
-1 byte thanks to @ovs.
Input as a list of lines, right-padded with spaces to an equal length.
Try it online or verify all test cases.
Explanation:
¬ # Get the first line of the (implicit) input-list (without popping)
g # Pop and push its length
6+ # Add 6
© # Store this value in variable `®` (without popping)
×ばつ '# Pop and create a string of that many "-"
a # Append it to the list of lines×ばつ # Create a string consisting of `®` amount of spaces
1 # Push 1
®Í # Push value `®` and decrease it by 2
‚ # Pair them together: [1,®-2]
'| ǝ '# Insert a "|" at those (0-based) indices in the spaces-string
IJ # Push the input-list, and join it to a single string
'd¢ '# Count the amount of "d"s in it
и # Repeat the legs-string that many times as list
« # And merge the two lists together
.c # And finally centralize this list, which adds leading spaces where
# necessary, and implicitly joins the list by newlines
# (after which the result is output implicitly)
-
-
\$\begingroup\$ Could you save anything by right padding the input with spaces so you'd just have to get the length of one line instead of the max length of all lines? \$\endgroup\$Shaggy– Shaggy2020年12月04日 11:18:55 +00:00Commented Dec 4, 2020 at 11:18
-
\$\begingroup\$ @Shaggy Thanks indirectly. 05AB1E doesn't really have any convenient builtins for right-padding unfortunately, except maybe the box builtin
.B(split string by newlines, and pad trailing spaces so all strings are the same length). Not really useful directly with my current approach, but in combination with the.c(centralize) builtin, it does save a byte in the end. AND, because taking the input already right-padded is allowed in the rules, an additional byte can be saved by just dropping the.B. \$\endgroup\$Kevin Cruijssen– Kevin Cruijssen2020年12月04日 11:58:35 +00:00Commented Dec 4, 2020 at 11:58
APL (Dyalog Unicode), (削除) 60 57 56 55 (削除ここまで) 41 bytes
{3⌽↑(↓'-'⍪⍨' '∘,⍣6⊢⍵),↓(+/∊'d'⍷⍵)6⍴' | '}
Input as a character matrix.
-1 byte from ovs.
-14 bytes, following xash's answer.
Explanation(old)
{↑(' '∘, ̈↓⍵),(⊂a/'-'),(+/∊'d'⍷⍵)/⊂2⌽'| |'↑⍨a←6+⊃⌽⍴⍵}
'| |' a set of table legs
↑⍨ pad to length
a←6+⊃⌽⍴⍵ 6 + row size
a← store in var a
⊂2⌽ rotate 2 steps and wrap
( )/ replicate that by:
'd'⍷⍵ boolean matrix of occurrences of 'data'
+/∊ sum all the occurrences
, concatenate with
(⊂a/'-') '-' repeated a times
(' '∘, ̈↓⍵), and the input padded with 3 spaces on the left
↑ convert to matrix(join with newlines)
Japt, (削除) 30 (削除ここまで) (削除) 28 (削除ここまで) 27 bytes
Hmm ... thought this would work out much shorter.
Takes input as an array of lines, right-padded with spaces and outputs an array of lines.
cU¬èd ô@S+i|i|úUÎÊ+3ÃvÈç-
û
cU¬èd ô@S+i|i|úUÎÊ+3ÃvÈç-\nû :Implicit input of array U
c :Concatenate
U¬ : Join U
èd : Count the "d"s
ô : Range [0,count]
@ : Map
S : Space
+ : Append
i : A space prepended with
|i : A "|" prepended with
|ú : A "|" right padded with spaces to length
UÎÊ+3 : Length of first element of U plus 3
à :End map
v :Modify first element
È :By passing it through the following function
ç- : Fill with "-"
\n :Reassign to U (saves a byte over having to close all the nested methods)
û :Centre pad each element with spaces to the length of the longest
J, 41 bytes
0 3|.(' | '$~6,~1#.'d'=,),~'-',~' '&,.^:6
How it works
' '&,.^:6prepend a space to each row 6 times.'-',~append a new row filled with-.1#.'d'=,count theds in the input.' | '$~6,~shape|into dimensionscount 6, socountrows of| |,~append the leg rows to the tables, filling possible empty space on the right with .0 3|.shift every row 3 characters to the left.
Or in pictures:
data
data
data
----------
data
----------
| |
data
-----------
| |
Ruby 2.7, (削除) 112 (削除ここまで) (削除) 98 (削除ここまで) (削除) 77 (削除ここまで) 74 bytes
Saved 6 bytes using String#count method, thanks to Razetime!
Saved 3 bytes using literal newline, thanks to Dingus!
->m{m.map{" "*3+_1}<<?-*(6+c=m[0].size)+"
| #{" "*c} |"*(m*"").count(?d)}
- TIO uses an older version of Ruby, while in Ruby 2.7, we've numbered parameters, i.e.,
_1, which saves 2 bytes.
-
1\$\begingroup\$ -6, just counting d \$\endgroup\$Razetime– Razetime2020年12月04日 09:22:41 +00:00Commented Dec 4, 2020 at 9:22
-
1
-
\$\begingroup\$ @Dingus - I was trying newline in
%[], didn't knew it works inside""too! \$\endgroup\$vrintle– vrintle2020年12月04日 13:36:14 +00:00Commented Dec 4, 2020 at 13:36
Python 3.8, (削除) 113 (削除ここまで) (削除) 107 (削除ここまで) 95 bytes
Saved (削除) 6 (削除ここまで) a whopping 18 bytes thanks to Dom Hastings!!!
lambda l:[' '+a for a in l]+[(r:=6+len(l[0]))*'-']+''.join(l).count('d')*[' |'+(r-4)*' '+'|']
Inputs a list of right-space-padded strings and returns a list of strings.
-
1\$\begingroup\$ +1 You can use
len(a)instead ofa.rfind('a')for -6 too! Try it online! \$\endgroup\$Dom Hastings– Dom Hastings2020年12月04日 13:11:40 +00:00Commented Dec 4, 2020 at 13:11 -
\$\begingroup\$ @DomHastings That's great and just realised I can require right padding for additional saves - thanks! :D \$\endgroup\$Noodle9– Noodle92020年12月04日 13:17:56 +00:00Commented Dec 4, 2020 at 13:17
-
\$\begingroup\$ Oh yeah, that's even easier then:
len(l[0])and saves me 8 bytes in my answer, thanks! \$\endgroup\$Dom Hastings– Dom Hastings2020年12月04日 13:28:37 +00:00Commented Dec 4, 2020 at 13:28
Jelly, 36 bytes
Ỵ6x3¤;ṄƊ€ẈṀ+©3"-xṄṛċ"d®e®’,2¤\þị)| Y
Takes input as a single string.
This is disgustingly hacked together, but Jelly's never been particularly good at strings.
How it works
Ỵ6x3¤;ṄƊ€ẈṀ+©3"-xṄṛċ"d®e®’,2¤\þị)| Y - Main link. Takes s on the left
Ỵ - Split into a list of lines
Ɗ€ - Over each line l:
¤ - Group together as a nilad:
6 - " "
x3 - [" ", " ", " "]
; - Prepend to l
Ṅ - Print
Ẉ - Get the lengths of each line
Ṁ - Take the maximum
+ 3 - Add 3
© - Save it to the register, r
"- - "-"
x - Repeat that many times
Ṅ - Print
ṛ - Discard everything and use s
ċ"d - Count occurrences of "d", d
® - Yield the register, r
\þ - Create an d×ばつr grid and to each cell (i, j):
¤ - Group into a nilad:
® - r
’ - r-1
2 - 2
, - [r-1, 2]
e - Is i in [r-1, 2]?
ị)| - Index each cell into "| "
Y - Join by newlines
Charcoal, (削除) 29 (削除ここまで) 25 bytes
WS⊞υι↑NoΣυdM←3Lθ←Fυ↑‖OOLθυ
Try it online! Link is to verbose version of code. Takes newline-terminated rectangular input. Explanation:
WS⊞υι
Input the data.
↑NoΣυdM←3
Print the left leg and the --- at the top of the left leg.
Lθ
Print the middle part of the table.
←Fυ↑
Move the cursor to the top right of the data. The following reflection will then move it to the top left. (Moving here avoids confusion between the use of the arrows as movement and as modifiers for reflection or printing direction.)
‖OOLθ
Reflect to complete the right of the table.
υ
Print the data.
-
\$\begingroup\$ Hm.. you'd also misinterpreted the question statement (like me :P). Actually, it says to print
namount of legs, wherenis number of times "data" appears in that multiline string/matrix. \$\endgroup\$vrintle– vrintle2020年12月04日 10:35:17 +00:00Commented Dec 4, 2020 at 10:35 -
\$\begingroup\$ @vrintle Thanks, I always seem to overlook something... \$\endgroup\$Neil– Neil2020年12月04日 10:43:30 +00:00Commented Dec 4, 2020 at 10:43
-
\$\begingroup\$ Japt should not be beating Charcoal in a challenge like this; try harder! :p \$\endgroup\$Shaggy– Shaggy2020年12月04日 23:58:54 +00:00Commented Dec 4, 2020 at 23:58
-
\$\begingroup\$ @Shaggy Yeah, I just spotted a trivial 4-byte saving without even trying... \$\endgroup\$Neil– Neil2020年12月05日 00:12:59 +00:00Commented Dec 5, 2020 at 0:12
C (gcc), (削除) 204 (削除ここまで) (削除) 194 (削除ここまで) (削除) 187 (削除ここまで) (削除) 181 (削除ここまで) 174 bytes
174-byte solution thanks to @ceilingcat.
z,s,i;main(c,v)char**v;{for(;++z<c;)printf(" %s\n",v[z]);for(;c--;)for(s=0;z=v[c][s++];)i+=z=='d';for(;z++<strlen(v[1])+6;putchar(45));for(;i--;)printf("\n |%*c",z-4,'|');}
Takes each line of input as a right-padded command line argument.
Retina, 53 bytes
\`.+
$&
L$`d
$%=
T`p`-
*0円G`
T`-`
%,T1,,-2` `|
Try it online! Takes rectangular input. Explanation:
\`.+
$&
Pad the input by 3 spaces on each side and print the result.
L$`d
$%=
Repeat each line by the count of its ds.
T`p`-
Change all the characters to -s.
*0円G`
Print the first line.
T`-`
Change all the characters to spaces.
%,T1,,-2` `|
Change the (0-indexed) second and second last characters to |s and implicitly print the resulting legs.
JavaScript (ES6), (削除) 105 (削除ここまで) 103 bytes
Expects a single string with right-padded lines.
s=>s[R='replace'](/^|t/g,c=>o+=`
`+(p=c?' | ':'---')+q[R](/./g,p[0])+p,o=s[R](/.+/g,s=>' '+(q=s)))&&o
Commented
s => // s = input string
s[R = 'replace']( // replace in s:
/^|t/g, // match the beginning of the string
// and each 't' (of 'data')
c => // for each matching character c:
o += // append to o:
`\n` + ( // a line-feed
p = // followed by p defined as:
c ? // if c is not empty:
' | ' // ' | '
: // else:
'---' // '---'
) //
+ q[R](/./g, // followed by each character in q ...
p[0]) // ... replaced with the 1st character of p
+ p, // followed by p
o = // initialize the output string o:
s[R]( // replace in s:
/.+/g, s => // each line s
' ' // with 3 leading spaces
+ (q = s) // followed by s, which is copied in q
) // end of replace()
) && o // end of replace(); return o
Perl 5 + -pl055F, 53 bytes
A different approach to @Xcali's answer. Requires lines to be padded with spaces.
$;+=y/d//;say" $_"}{$\=$\x(6+($#x=@F))."
| @x |"x$
Explanation
Firstly, -l055 sets $\ to '-', -p implicitly wraps wraps the code in while(<STDIN>){...;print;} and -F splits each line of input into chars in @F.
In the code, due to the implicit code added by -p, for each line of text increment $; with the number of d in the code then say the line with three leading spaces. The }{ breaks out of the implicit while and $\ is then set to $\ repeated 6+@F (whilst also setting $#x to @F's scalar value) times concatenated with a string consisting of: a leading newline, space, pipe (|), space, @x interpolated, space, pipe, which itself it repeated $; times.
@F, when used in a scalar context like this, returns the number of elements in @F - which is the number of chars in the line, since each line is space-padded this works fine. $#x is a 'magic' variable which contains the last index of @x and means that @x now contains @F+1 empty values. When an array is interpolated into a double-quoted string, its values are printed out with a space between each, so an empty array with @F+1 elements interpolated, results in a string consisting of @F spaces. This code ends with just $ because of the -p-added code which contains ; saving another byte.
Vyxal ao, 34 bytes
ƛ3Ip...L;G:3+\-*,‹‛ƛ↓□しろいしかく⁋ẎL$I‛ |p‛|
+*
Try it Online! Probably not optimal, but beats Jelly :P
a flag is for multiline input; o forces implicit output even though there are print statements in the code.
ƛ3Ip...L;G:3+\-*,‹‛ƛ↓□しろいしかく⁋ẎL$I‛ |p‛|
+* # Full program
ƛ ; # For each line in input (`a` flag):
3Ip # Prepend 3 spaces
... # Print ^
L # and return its length
G: # Take the maximum length from ^ and duplicate
3+ # Add 3 to one copy
\-*, # Print that many `-`s
‹ # Decrement the other maximum length copy for later
□しろいしかく⁋ # From inputs...
ẎL # ...find the number of
‛ƛ↓ # ...`data`s (dictionary-compressed)
$ # Swap number of "data"s for (maximum length - 1)
I # Push that many spaces
‛ |p # Prepend " |" to ^
‛|\n+ # Append "|\n" to ^ (\n is an actual newline)
* # Repeat as many times as the number of datas to make the legs
# `o` flag - implicitly output the legs of the table
Pip, 36 bytes
P'-M@P*gWRsX3LXW*4N JgPsX#a+2WR'|WRs
Takes lines of input as command-line arguments; or, with the -r flag, as lines of stdin. Lines must be padded with spaces to the same length. Try it online!
Explanation
Let's break this into two halves: the data + tabletop, and the legs.
P'-M@P*gWRsX3
g List of input lines
WR Wrap each line in
sX3 Three spaces
P* Print each line
@ Take the first one
'-M List containing one hyphen for each character in that line
P Print (concatenated together by default)
LXW*4N JgPsX#a+2WR'|WRs
Jg Join the lines of input into one string
N Count occurrences in that string of
XW Regex matching [a-zA-Z0-9]
*4 repeated 4 times
L Loop that many times:
a First line of input
# Length
+2 Plus 2
sX String of that many spaces
WR'| Wrap in pipe characters
WRs Wrap in spaces
P Print
" data ","data \n data". \$\endgroup\$