25
\$\begingroup\$

Given a 2-dimensional jagged array and a fill value, pad the array in both dimensions with the fill value to ensure that it is square and not jagged (i.e., all rows are the same length, and that length is the same as the number of rows).

The fill values should always be added to the "edges", which may be the start or the end, but not in the middle.

For example, with the fill value 8, this array:

[[1, 5, 3],
 [4, 5],
 [1, 2, 2, 5]]

could become:

[[1, 5, 3, 8],
 [4, 5, 8, 8],
 [1, 2, 2, 5],
 [8, 8, 8, 8]]

Here is another valid output:

[[8, 8, 8, 8],
 [8, 1, 5, 3],
 [8, 4, 5, 8],
 [1, 2, 2, 5]]

However, the padding should be minimal: the size of the output square should be equal to the maximum of the length of the rows and the number of rows. For example, this is not a valid output for the input above:

[[1, 5, 3, 8, 8],
 [4, 5, 8, 8, 8],
 [1, 2, 2, 5, 8],
 [8, 8, 8, 8, 8],
 [8, 8, 8, 8, 8]]

More test cases

All using fill value 0 for simplicity.

Input:
[]
Output:
[]
Input:
[[],
 []]
Output:
[[0, 0],
 [0, 0]]
Input:
[[5]]
Output:
[[5]]
Input:
[[0, 0],
 [0],
 [0, 0, 0]]
Output:
[[0, 0, 0],
 [0, 0, 0],
 [0, 0, 0]]
Input:
[[1, 2, 3, 4]]

Output:
[[1, 2, 3, 4],
 [0, 0, 0, 0],
 [0, 0, 0, 0],
 [0, 0, 0, 0]]
Input:
[[1],
 [2],
 [3],
 [4, 5]]
Output:
[[1, 0, 0, 0],
 [2, 0, 0, 0],
 [3, 0, 0, 0],
 [4, 5, 0, 0]]

Rules

  • The array's elements and the fill value can be of whatever type or set of values you like, as long as there are at least two distinct possibilities. For example, you could use characters, where the array is a multi-line string (where each line is a row), or you could restrict the values to single digits...
  • Standard loopholes are forbidden
  • Standard I/O rules apply
  • This is , so the shortest code in bytes wins
\$\endgroup\$
3
  • \$\begingroup\$ Sandbox \$\endgroup\$ – pxeger Feb 15 at 12:43
  • 5
    \$\begingroup\$ How about an input with 0 rows and 3 columns? :-) \$\endgroup\$ – Adám Feb 15 at 12:56
  • \$\begingroup\$ @Adám that can't be represented in a nested array unless the language supports undefined array values, so it doesn't need to be handled \$\endgroup\$ – pxeger Feb 15 at 12:59

26 Answers 26

6
\$\begingroup\$

K (ngn/k), 21 19 bytes

{y^x .!'2#|/#'x,,x}

Try it online!

  • |/#'x,,x get the size of the output (i.e. the maximum of the count of each row, and of the number of rows)
  • !'2# build a list of two copies of 0..size (e.g. (0 1 2 3;0 1 2 3))
  • x . dot-apply into the input (out of bound accesses result in 0Ns)
  • y^ replace nulls with the fill number
\$\endgroup\$
8
\$\begingroup\$

Haskell, 67 bytes

m%v|let l?x=take(maximum$length<$>(1<$m):m)$l++repeat x=(?v)<$>m?[]

Try it online!

\$\endgroup\$
5
\$\begingroup\$

J, 25 bytes

4 :'y([{.!.x&>{.)~>./$>y'

Try it online!

Note: -3 off TIO for f=.

Note that in J ragged arrays must be boxed.

This was surprisingly hard considering that J auto fills ragged arrays by default. Unfortunately, the default behavior is not quite enough for what's needed in this challenge.

how

We take the fill as the left arg x and the input arrays as the right arg y, and use an explicit (rather than tacit) verb because the fit conjunction !. required to specify fill requires a value or named variable.

  • >./$>y - The max >./ of the dimensions $ of the opened input >y. We'll use this as the left argument of the main verb.
  • ([ {.!.x&> {.) The main verb, consisting of a fork whose right tine {. expands the boxed input to the required dimension by filling it with blank boxes. This handles what will ultimately become the "vertical expansion".
  • {.!.x&> For each box &> (the original input, plus the empty expansions produced in the previous step), take {. the required length, filling missing items with the specified fill !.x. This handles the "horizontal expansion".
\$\endgroup\$
5
\$\begingroup\$

JQ, 49 bytes

Takes input as an array of [array, fill-element], where the array can hold any non-null type.

.[1]as$a|.[0]|transpose|transpose|map(map(.//$a))
EXPLANATION:
.[1]as$a|  # input array's second argument is in variable a
         .[0]|  # the first argument
              transpose|  # transposed, automatically placing null as a fill element
                        transpose|  # back to normal
                                  map(      # for each row
                                      map(  # for each element
                                          .//$a  # if it's null, the fill element, else it.
# // is like or in other languages, . means "it" or "it unchanged"

https://jqplay.org/s/8ADEt9WJGL

\$\endgroup\$
5
\$\begingroup\$

JavaScript (ES6), 92 bytes

Expects (array)(value), where array contains positive integers (or any other truthy values).

a=>v=>[a,...a].sort((a,b)=>b.length-a.length)[0].map((_,y,A)=>A.map((_,x)=>(a[y]||0)[x]||v))

Try it online!

Commented

a =>                  // a[] = jagged array
v =>                  // v = fill value
[a, ...a]             // build an array consisting of the jagged array itself
                      // followed by each of its rows
.sort((a, b) =>       // sort this array ...
  b.length - a.length //   ... from longest to shortest entry
)[0]                  // and keep the longest one
.map((_, y, A) =>     // for each row at position y in this array A[]:
  A.map((_, x) =>     //   for each entry at position x in A[]:
    (a[y] || 0)[x]    //     attempt to get the value at (x, y) in a[]
    || v              //     if it fails, use the fill value instead
  )                   //   end of inner map()
)                     // end of outer map()
\$\endgroup\$
4
  • \$\begingroup\$ 92 bytes if you limit the input to truthy values only - Try it online! \$\endgroup\$ – pxeger Feb 16 at 10:52
  • \$\begingroup\$ @pxeger That's what I was doing in my very first version (I added the 1/q test during the grace period of the initial post). But I think it's hard to tell whether it's allowed or not to expect 'falsy' vs 'truthy' with the current rules. \$\endgroup\$ – Arnauld Feb 16 at 11:04
  • \$\begingroup\$ "The array's elements can be of whatever type you like, as long as there exist at least two distinct values for that type" - positive integers only is a perfectly acceptable type! \$\endgroup\$ – pxeger Feb 16 at 11:05
  • 1
    \$\begingroup\$ @pxeger Ok then. But I think you should clarify the meaning of "type". (My understanding was "language type", not "mathematical type".) \$\endgroup\$ – Arnauld Feb 16 at 11:07
5
\$\begingroup\$

R, 80 90 93 88 bytes

Edit: -5 bytes thanks to Kirill L., but only after +10 bytes to fix bug, and +3 more bytes after belatedly realising that the fill-value should be given as input...

function(l,f,m=matrix(f,d<-max(0,seq(l),lengths(l)),d)){for(i in l)m[F<-F+1,seq(i)]=i;m}

Try it online!

\$\endgroup\$
2
  • 1
    \$\begingroup\$ Save some bytes by a yet another approach to length. Unfortunately, we have to include 0 for the case of empty input... \$\endgroup\$ – Kirill L. Feb 16 at 17:32
  • \$\begingroup\$ @KirillL. Thanks! Nice trick with seq! \$\endgroup\$ – Dominic van Essen Feb 16 at 18:44
4
\$\begingroup\$

APL (Dyalog Extended), 26 bytes (SBCS)

Anonymous infix lambda, taking fill as left argument and array as right argument.

{g←1⌷∘↑↑⍮∘⍉↑⋄⍺@(⍸~g=⍨⍵)g⍵}

Try it online!

{} dfn; left argument (fill) is , right argument (array) is

g← define g as a tacit function:

  1⌷∘ the first layer of the 3D array that consist of

    the 3D array consisting of the following two layers, padded with 0s:

  ↑⍮∘⍉ the 2D array consisting of the given rows, padded with 0s, and the transposed…

    2D array consisting of the given rows, padded with 0s

 then:

⍺@() place fills at the indices given by:

   the ɩndices where…

  ~ there are zeros (lit. NOT)…

  g in the fully padded version of…

  =⍨ the array identical to the given one, but with all elements made into 1s (lit. self-equality)

g⍵ in the fully padded given array

\$\endgroup\$
4
\$\begingroup\$

APL(Dyalog Unicode), 47 37 32 bytes SBCS

{⍺@((,⍳x)~⍸↑=⍨⍵)⊢(x←2/⌈/⍴↑⍵)↑↑⍵}

Try it on APLgolf!

A dfn submission which takes fill element on the left, and ragged array on the right.

It calculates the indices of the existing elements and replaces everything else with the fill element.

-10, borrowing an idea from Adám's answer.

-5 from user.

\$\endgroup\$
0
4
\$\begingroup\$

Functional Bash*, 167 161 147 bytes

* This is bash with the additional constraint that you can't mutate variables.

-14 bytes thanks to pxeger

m=`sort -n <(awk '{print NF}' $1) <(wc -l<$1)|tail -1`
s=`seq $m`
paste -d\  $1 <(printf "`printf "$2 %.s" $s`\n%.s" $s)|sed s/^\ //|cut -d\  -f-$m

Try it online!

The two arguments are:

  • $1: file name containing lines of input
  • $2: The fill character

The basic approach is to get the side length of the square (stored in m) and then create an m x m file of the fill, paste it with the original file, and take m fields from each line.

Would love to know if there's a terser approach.

\$\endgroup\$
6
  • \$\begingroup\$ I'd recommend you to check out the Tips for golfing in Bash; I've got this down to 143 without changing the approach (Try it online!), and you can save a fair few more by switching to zsh (if you're wiling to, of course) \$\endgroup\$ – pxeger Feb 16 at 8:16
  • \$\begingroup\$ Thanks. Appreciate it as I only golf in bash occasionally. I'll update this tomorrow with your suggestions. \$\endgroup\$ – Jonah Feb 16 at 8:20
  • \$\begingroup\$ @pxeger Looking at this now, and while there are tricks I can adapt to save bytes, the TIO link you included has incorrect output for most test cases. Am I missing something? \$\endgroup\$ – Jonah Feb 16 at 16:25
  • \$\begingroup\$ I got carried away using zsh-isms, before realising you might not want to switch languages (especially given you specified "functional" bash), so I switched back but evidently didn't pay too much attention. Fixed version: Try it online! \$\endgroup\$ – pxeger Feb 16 at 16:28
  • \$\begingroup\$ Thank you. They all look correct now except the first test case, which is not supposed to have fill. \$\endgroup\$ – Jonah Feb 16 at 16:32
3
\$\begingroup\$

Charcoal, 27 bytes

≔⌈⊞OEηLιLηζIE…⁺ηEζυζ…⁺ιEζθζ

Try it online! Takes the fill as first input and the jagged array as second input, but they can be trivially reversed if necessary. Outputs using Charcoal's default array format, which is each element on a separate line with rows double-spaced from each other. Explanation:

≔⌈⊞OEηLιLηζ

Take the length of each element of the jagged array, tack on the length of the array itself, and then take the maximum of the result.

IE…⁺ηEζυζ…⁺ιEζθζ

Concatenate an array of empty arrays to the jagged array, then chop to the desired length. For each element of that array, concatenate an array of the fill value, then chop to the desired length. Print the result.

\$\endgroup\$
3
\$\begingroup\$

Jelly, 8 bytes

ṭ`zṖ€ɗ⁺⁹

A dyadic Link accepting a, possibly jagged, two-dimensional array on the left and a fill value on the right which yields a square array which is filled rightwards and downwards with the fill value.

Try it online! (Footer added to format the resulting array, so that one can see the empty case work.)

How?

ṭ`zṖ€ɗ⁺⁹ - Link: array, A; filler, F
       ⁹ - use the right argument, F, as the right argument of:
           (seems to be required for the ⁺, below)
      ⁺  -   repeat this link twice:
     ɗ   -     last three links as a dyad - f(current A, F):
  `      -       use left (A) as both arguments of:
 ṭ       -         tack - e.g. [[1],[2,3]] -> [[1],[2,3],[[1],[2,3]]]
                   (only thing that matters is that the tacked list has the length of A)
   z      -      transpose with filler (F) -> rectangular array right-filled.
    Ṗ€    -      pop an element off of each (removing the tacked lists)
\$\endgroup\$
3
\$\begingroup\$

05AB1E, 18 17 8 bytes

2FDªI怨

-9 bytes by porting @JonathanAllan's Jelly answer, so make sure to upvote him as well!

Try it online or verify all test cases.

Previous 17 bytes answer:

Dª€gà©nи®ô¹ì²ζø®∍

Try it online or verify all test cases.

Explanation:

2F                 # Loop 2 times:
  D                #  Duplicate the current matrix
                   #  (which will be the implicit input-matrix in the first iteration)
   ª               #  Append the matrix to itself
     ζ             #  Zip/transpose; swapping rows/columns,
    I              #  using the second input-character as filler
      ۬           #  And then remove the last item of each row
                   # (after the loop, the resulting matrix is output implicitly)

D                  # Duplicate the first (implicit) input-matrix
 ª                 # Append the matrix to itself
  €                # Map over each inner list:
   g               #  Pop and push its length
    à              # Pop and push the maximum
                   # (we now have the dimension of the output-square, which is either
                   #  equal to the amount of rows or amount of columns, whichever of
                   #  the two is larger)
     ©             # Store this maximum in variable `®` (without popping)
      n            # Square it
       и           # Repeat the second (implicit) input that amount of times as list
        ®ô         # Split it into parts of size `®`
          ¹ì       # Prepend the first input-matrix at the front
             ζ     # Zip/transpose; swapping rows/columns,
            ²      # using the second input-character as filler
              ø    # And then zip/transpose the rows/columns back
               ®∍  # Shorten the matrix to the first `®` amount of rows
                   # (after which the resulting matrix is output implicitly)
\$\endgroup\$
3
\$\begingroup\$

Python 2, 75 bytes

def f(M,v):n=max(map(len,M+[M]));print[(r+[v]*n)[:n]for r in(M+[[]]*n)[:n]]

Try it online!

\$\endgroup\$
5
  • \$\begingroup\$ I was able to reduce your code by 2 bytes, can I count on a reward? \$\endgroup\$ – Danis Feb 19 at 16:53
  • \$\begingroup\$ @Danis Yes, assuming it's also in Python 2. Looking forward to what you have! \$\endgroup\$ – xnor Feb 19 at 23:52
  • \$\begingroup\$ Okay, I changed my mind, I don't need 50 reputation. To save one byte, you need to get rid of the parentheses after the for \$\endgroup\$ – Danis Feb 20 at 8:26
  • \$\begingroup\$ @Danis Which parentheses? \$\endgroup\$ – xnor Feb 20 at 9:01
  • \$\begingroup\$ Oh, I see, you move the [:n] to the outside of the list comp first, then you can remove the parentheses. That's nifty. Still feel free to post an answer and I'll give the bounty, but up to you. \$\endgroup\$ – xnor Feb 20 at 9:03
2
\$\begingroup\$

Charcoal, 15 14 bytes

UO⌈⊞OEθLιLθηPθ

Matrix-input as a list of string-rows; filler-character as string input; and output as a printed multi-line string, which is allowed based on the first rule.

Try it online (verbose) or try it online (pure).

Explanation:

Determine the length of each row, the amount of rows, and then only leave the maximum of those combined:

Maximum(PushOperator(Map(q, Length(i)), Length(q)))
⌈⊞OEθLιLθ

Draw a square of that size, using the second input-character as filler:

Oblong(..., h)
UO...η

Then print the first input on top of that to finish the intended result:

Multiprint(q)
Pθ
\$\endgroup\$
2
\$\begingroup\$

Scala, 75 bytes

a=>p=>{val m=(a.map(_.size):+a.size).max
a.padTo(m,Seq())map(_.padTo(m,p))}

Try it online!

Scala, 108 bytes

a=>p=>{val m=a.map(_.size)./:(a.size)(_ max _)
Seq.tabulate(m,m)((i,j)=>scala.util.Try(a(i)(j))getOrElse p)}

Try it online!

\$\endgroup\$
3
  • 1
    \$\begingroup\$ Try this for 103 bytes (fold -> /:, math.max -> _ max _, and infix getOrElse) \$\endgroup\$ – user Feb 15 at 22:55
  • 1
    \$\begingroup\$ Eh, still a lot more than the top solution :P By the way, you can omit the . but you need to add a=>p=> for 81 bytes. \$\endgroup\$ – user Feb 15 at 23:06
  • 1
    \$\begingroup\$ 75 bytes! \$\endgroup\$ – user Feb 17 at 19:10
2
+100
\$\begingroup\$

Zsh, 91 83 bytes

wc<I -lL|read l w
repeat w-l
echo>>I
while read i
do<<<${(pr/l>w?l:w//$1/)i}
done<I

Try it online!

Works character-wise, taking input from a file I and the first command-line argument.

This was going to be a suggestion to Jonah's Bash answer, but it became sufficiently different that I thought I'd post it separately.

  • wc -lL - output the number of lines and the maximum line length
  • <I - from the file I
  • |read l w - and store those values in the variables l and w respectively
  • repeat w-l - repeat [the difference between w and l] times:
    • echo - print a blank line
    • >>I - append that to the file I
    • this adds extra blank rows if needed; because if w-l is negative, the repeat won't execute at all
  • while read i do done<I - for each line in I:
    • ${i} - take that line, and
    • (p) - substituting in the values of m and 1,
    • (r/l>w?l:w//$1/) - pad on the right using the character $1 to the length l>w?l:w
      • l>w?l:w is the maximum line length and number of lines.
    • <<< - and print that line
\$\endgroup\$
2
\$\begingroup\$

Lua, 205 187 bytes

load("t=".. ....."c=#t for i=1,c do c=math.max(c,#t[i])end p=io.write p'{'for i=1,c do for j=1,c do _=j==1 and p'{'p(t[i]and t[i][j]or 0)p(j==c and'}'or',')end _=i~=c and p','end p'}'")()

Try it online!

Human readable code:

load(
  "t=".. .....
  "c=#t
   for i=1,c do
     c=math.max(c,#t[i])
   end
   p=io.write
   p'{'
   for i=1,c do 
     for j=1,c do
       _=j==1 and p'{'
       p(t[i]and t[i][j]or 0)
       p(j==c and'}'or',')
     end
     _=i~=c and p','
   end
   p'}'
  ")
()
\$\endgroup\$
2
  • \$\begingroup\$ This is a full program because "(...)" will capture command-line arguments (example) \$\endgroup\$ – wen1k May 4 at 10:37
  • \$\begingroup\$ Thanks for the clarification. I misunderstood what was happening with t and value in your TIO link. \$\endgroup\$ – Dingus May 4 at 12:01
2
\$\begingroup\$

Vyxal, 33 32 29 10 bytes

2(:wJ⁰ÞṪvṪ

Try it Online!

Thanks to lyxal for -23 bytes.

\$\endgroup\$
9
  • \$\begingroup\$ ƛL;vL, ƛh;vh for -2 \$\endgroup\$ – lyxal May 25 at 7:26
  • \$\begingroup\$ Try it Online! for 29 \$\endgroup\$ – lyxal May 25 at 7:37
  • \$\begingroup\$ but surely there has to be some way of doing this registerless \$\endgroup\$ – lyxal May 25 at 7:38
  • \$\begingroup\$ @lyxal Maybe... - my current approach relies on appending digits to the array that is ToS... Thanks for the golfs! \$\endgroup\$ – A username May 25 at 7:54
  • \$\begingroup\$ Try it Online! for 10 \$\endgroup\$ – lyxal May 25 at 7:56
1
\$\begingroup\$

Canvas, 16 bytes

⁸)⁸∔0;{LM}⁷;:*⁸n

Try it here!

Takes an array of strings and a filler string as input.

\$\endgroup\$
1
\$\begingroup\$

Julia, 82 bytes

f(a,b,L=max(length.([a;[a]])...),B=fill(b,L))=[(x->[x;B][1:L]).(a);fill(B,L)][1:L]

Try it online!

\$\endgroup\$
1
\$\begingroup\$

Python 3, 83 bytes

def f(l,v):x=max(map(len,l+[l]));return[a+[v]*(x-len(a))for a in l+[[]]*(x-len(l))]

Try it online!

\$\endgroup\$
0
1
\$\begingroup\$

C (gcc) with -m32, 173 163 bytes

Thanks to ceilingcat for -10.

Takes an NULL-terminated array of strings and fill character, and returns a NULL-terminated array of padded strings with number of rows equal to the string length.

The function scans each string to find the longest length, then creates a destination array of the largest of the row count and maximum string length, plus 1. For each row, a string containing the fill character is allocated and generated, with the original string contents (minus the trailing NUL) then copied over the new string. The generated array is then returned to the caller.

*b,r,c,l;f(s,f)int*s;{for(r=c=0;s[r];)c=fmax(strlen(s[r++]),c);for(c=r=r>c?r:c,l=b=calloc(c+1,4);r--;*s?*stpcpy(*b,*s++)=f:0,b++)memset(*b=calloc(c+1,1),f,c);s=l;}

Try it online!

\$\endgroup\$
0
1
\$\begingroup\$

Japt, 14 bytes

Takes an array of strings plus a single string as input, outputs an array of strings.

I spent five bytes finding the length of the longest string in the input, I would expect that to be somewhat crunchable.

úV ÕúVUñÊo Ê y
ú              // Right-pad every item in the first input to the length of the longest one
 V             // using the second input.
   Õ           // Transpose the rows with the columns,
    ú          // then right-pad every item again as above, except this time
           Ê   // pad to the length
       ñÊo     // of the longest item (sort by length, get the last item)
      U        // in the first input
     V         // using the second input as padding.
             y // Finally, transpose back and implicitly output the result.

Try it out here.

\$\endgroup\$
1
\$\begingroup\$

Husk, 13 14 12 14 bytes

Edit: +1 byte to fix bug, then -2 bytes using a different approach, but then +2 bytes after realising we need to provide the fill-value as an argument

₁₁²¹
T⁰ż+³RøLT

Try it online!

How?

    ₁₁          # apply helper function ₁ twice
                # helper function:
    T0          # transpose, padding with zeros,
      ż+¹       # input list zipped by element-wise concatenation with
         Rø     # a list of empty lists,
           LT   # as long as the longest list in the input list

Note after reading the other answers: I realised that a port of Jonathan Allan's approach is 1 byte shorter at 11 13 bytes...

\$\endgroup\$
1
\$\begingroup\$

JavaScript (Node.js), 80 bytes

a=>v=>a.map(g=A=>A.map((_,i)=>A.map((_,j)=>x[j]=x[j]||v,x=a[i]=a[i]||[])))&&g(a)

Try it online!

JavaScript (Node.js), 82 bytes

a=>v=>[a,...a].map(A=>A.map((_,i)=>A.map((_,j)=>x[j]=x[j]||v,x=a[i]=a[i]||[])))&&a

Try it online!

Can omit &&a claiming return to where a was

\$\endgroup\$
0
\$\begingroup\$

APL, 34 30 bytes

{M↑M↑¨(,∘S¨⍵),M/¨S←⍺⍴⍨M←⌈/⍴↑⍵}

Try it online!

Might as well put my own APL answer here, even if it is longer than Adám's. Takes vectors of vectors, and outputs vectors of vectors. The output with [] is a little funky as a result of this, the output is still [], but it would be something akin to an empty vector of vectors.

-4 bytes thanks to looking at a portion of Razetime's answer.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.