16
\$\begingroup\$

Given a rectangular grid of text, line up the diagonals that go from the upper-left to the bottom-right into columns such that the lowest-rightmost characters of all diagonals are on a level. Use spaces for indentation.

For example, if the input grid of text is

abcd
1234
WXYZ

then you'd line up the diagonals W, 1X, a2Y, b3z, c4, and d in columns giving this output:

 ab
 123c
WXYZ4d

Note that the lowest-rightmost characters of all diagonals, WXYZ4d, are at the same level.

Details

  • The input grid of text will be at minimum 1×1 in size and all lines will be the same length.

  • You may take the input grid as a multiline string or as a list of single line strings.

  • The input grid will only contains printable ASCII characters (includes space).

  • The output may optionally have one trailing newline but there should be no other empty lines.

  • The lines of the output may optionally have trailing spaces but should not have unnecessary leading spaces.

Other Examples

Empty lines separate examples. Each input is directly followed by its output.

123
456
789
 1
 452
78963
123.?!
456??!
789!!!
 123.
 456???
789!!!!!
**@
@ 
 **
@ @
/\/\
\/ /
/ /\
\/\/
 /
 \/\
 / / /
\/\/\/\
12
34
56
78
90
 7531
908642
Code
Code
G
O
L
F
FLOG
~
~

Scoring

The shortest code in bytes wins.

asked Dec 27, 2016 at 9:01
\$\endgroup\$
6
  • \$\begingroup\$ Related. Related tip. \$\endgroup\$ Commented Dec 27, 2016 at 9:50
  • \$\begingroup\$ Can the input be a 2D char array (a matrix of chars)? \$\endgroup\$ Commented Dec 27, 2016 at 13:14
  • \$\begingroup\$ Can the first column of the input contain spaces? \$\endgroup\$ Commented Dec 27, 2016 at 14:56
  • \$\begingroup\$ @LuisMendo That sounds ok. \$\endgroup\$ Commented Dec 27, 2016 at 21:29
  • \$\begingroup\$ @KritixiLithos Yes, it might. \$\endgroup\$ Commented Dec 27, 2016 at 21:29

12 Answers 12

5
\$\begingroup\$

J, 12 bytes

|./.&.|:&.|.

Defines an anonymous verb. Try it online!

Explanation

|./.&.|:&.|.
|. Reversed
 /. anti-diagonals
 &. under
 |: transpose
 &. under
 |. reversal

In J, u &. v (read: u under v) means "v, then u, then inverse of v". Reversal and transpose are self-inverses, so the program really means "reverse, transpose, extract reversed anti-diagonals, transpose, reverse".

With example input:

abcd
1234
WXYZ

Reverse:

WXYZ
1234
abcd

Transpose:

W1a
X2b
Y3c
Z4d

Extract reversed anti-diagonals (and pad with spaces):

W 
X1 
Y2a
Z3b
4c 
d 

Transpose:

WXYZ4d
 123c 
 ab 

Reverse:

 ab 
 123c 
WXYZ4d
answered Dec 27, 2016 at 10:09
\$\endgroup\$
2
  • 2
    \$\begingroup\$ Excellent demonstration of the power of adverbs \$\endgroup\$ Commented Dec 27, 2016 at 10:28
  • 2
    \$\begingroup\$ I woke up and remembered those were actually conjunctions. \$\endgroup\$ Commented Dec 27, 2016 at 21:01
2
\$\begingroup\$

Jelly, 11 or 10 bytes

ZŒDṙLUz6ṚUY

Try it online!

A fairly different algorithm from my other solution; this one uses a builtin to get at the diagonals, rather than doing things manually.

Explanation:

ZŒDṙLUz6ṚUY
Z transpose
 ŒD diagonals, main diagonal first
 L number of lines in the original array
 ṙ rotate list (i.e. placing the short diagonal first)
 U reverse inside lines
 z6 transpose, padding with spaces
 ṚU rotate matrix 180 degrees
 Y (possibly unnecessary) join on newlines

The diagonals come out in possibly the worst possible orientation (requiring repeated transpositions, reversals, and rotations), and in the wrong order (Jelly outputs the main diagonal first, so we have to move some diagonals from the end to the start to get them in order). However, this still comes out shorter than my other Jelly solution.

answered Dec 30, 2016 at 8:37
\$\endgroup\$
2
\$\begingroup\$

CJam, 29 bytes

qN/{)\z}h]2/{~W%+}%eeSf.*W%N*

Try it online!

Explanation

Instead of extracting the diagonals, we peel off layers from the end, alternating left and right. Consider the following input:

GFDB
EEDB
CCCB
AAAA

If we write out the diagonals as required by the challenge, we get:

 G
 EEF
 CCCDD
AAAABBB

Note that this is simply (from bottom to top), the bottom-most row, concatenated with the right-most column. This definition also works if the input is rectangular.

{ e# Run this loop while there are still lines left in the input.
 ) e# Pull off the bottom-most row.
 \ e# Swap with the remaining rows.
 z e# Transpose the grid so that the next iteration pulls off the last
 e# column instead. However, it should be noted that transposing
 e# effectively reverses the column, so the second half of each output
 e# line will be the wrong way around. We'll fix that later.
}h e# When the loop is done, we'll have all the individual layers on the
 e# stack from bottom to top, alternating between horizontal and vertical
 e# layers. There will be an empty string on top.
] e# Wrap all those strings in a list.
2/ e# Split into pairs. There may or may not be a trailing single-element
 e# list with the empty string.
{ e# Map this block over each pair...
 ~ e# Dump the pair on the stack.
 W% e# Reverse the second element.
 + e# Append to first element.
 e# If there was a trailing single-element list, this will simply
 e# add the empty string to the previous pair, which just removes
 e# the empty string.
}%
ee e# Enumerate the list, which pairs each string (now containing both halves)
 e# of an output line from bottom to top) with its index.
Sf.* e# Turn those indices X into strings of X spaces, to get the correct
 e# indentation.
W% e# Reverse the list of strings so the longest line ends up on the bottom.
answered Dec 27, 2016 at 12:48
\$\endgroup\$
3
  • \$\begingroup\$ Careful, that ] will wrap the entire stack! I think functions should work regardless of the stack contents beneath the input, and you seem to agree ^^ \$\endgroup\$ Commented Dec 30, 2016 at 15:49
  • \$\begingroup\$ @Lynn whoops, forgot that I was using ] when I changed it to a function. \$\endgroup\$ Commented Dec 30, 2016 at 15:53
  • \$\begingroup\$ I think you could do [{)\z}h] and keep it a function, for 27 bytes. \$\endgroup\$ Commented Dec 30, 2016 at 16:37
2
\$\begingroup\$

JavaScript, (削除) 116 (削除ここまで) 101 bytes

f=(s,r='$&',l='',z=s.replace(/.$|\n?(?!.*\n)..+/gm,x=>(l=x+l,'')))=>l?f(z,r+' ')+l.replace(/\n?/,r):l
G.onclick=()=>O.textContent=f(I.value);
<textarea id=I style=height:100px>/\/\
\/ /
/ /\
\/\/</textarea><button id=G>Go</button><pre id=O></pre>

I just wanted to use this regex pattern /.$|\n?(?!.*\n)..+/gm idea. (https://regex101.com/r/mjMz9i/2)

JavaScript regex flavour is disappointing, I had to use (?!.*\n) because it doesn't have \Z implemented, and somehow I didn't get to use 0円.

  • 15 bytes off thanks @Neil.
answered Dec 28, 2016 at 17:53
\$\endgroup\$
3
  • \$\begingroup\$ I just love this approach, but you can use . instead of [^] since you only need to skip non-newline characters to find a newline, which saves 2 bytes. \$\endgroup\$ Commented Jan 1, 2017 at 18:52
  • \$\begingroup\$ I don't think the ^ is necessary in the final regex, because any \n is already at the beginning of the string anyway, so that saves another byte. \$\endgroup\$ Commented Jan 1, 2017 at 18:54
  • \$\begingroup\$ I've come up a way to golf the '$&'+' '.repeat(n). Basically that expression is just $& but with a space added each call, which is trivial to implement recursively - replace n=0 with r='$&' and f(z,n+1) with f(z,r+' ') and then r is the desired replacement string. If I've counted correctly that saves 12 bytes. \$\endgroup\$ Commented Jan 1, 2017 at 18:58
1
\$\begingroup\$

Jelly, 15 or 14 bytes

L’6x;\Ṛ;"μZUZṚY

Try it online!

This is an algorithm that doesn't use Jelly's built-in for diagonals. Doing that might make it shorter; I might well try that next.

Here's how the algorithm works. Let's start with this input:

["abc",
 "def",
 "ghi"]

We start off with L’6x;\. L’ gives us the length of the input minus 1 (in this case, 2). Then 6x gives us a string of spaces of that length (" " in this case); and ;\ gives us the cumulative results when concatenating it (a triangle of spaces). We then reverse the triangle and concatenate it to the left side of the original (;" concatenates corresponding elements of lists, μ forcibly causes a break in the parsing and thus uses the original input as the second list by default), giving us this:

[" abc",
 " def",
 "ghi"]

This is almost the solution we want, but we need to move the elements downwards to be flush with the last string. That's a matter of transposing (Z), reversing inside each line (U), transposing again (Z), and reversing the lines ():

[" abc",
 " def",
 "ghi"]

transpose

[" g",
 " dh",
 "aei",
 "bf",
 "c"]

reverse within rows

["g ",
 "hd ",
 "iea",
 "fb",
 "c"]

transpose

["ghifc",
 " deb",
 " a"]

reverse the rows

[" a",
 " deb",
 "ghifc"]

Finally, Y joins on newlines. It's unclear to me whether or not this is required to comply with the specification (which allows input as a list of strings, but doesn't say the same about output), so the exact byte count depends on whether it's included or omitted.

answered Dec 30, 2016 at 8:13
\$\endgroup\$
1
\$\begingroup\$

Pyth, 16 bytes

j_.t_M.Tm+*;l=tQ

Big Pyth:

join-on-newline
reverse transpose-and-fill-with-spaces reverse func-map transpose-justified
map
 plus
 times innermost-var
 length assign tail input
 implicit-innermost-var
 implicit-input

Since people say golfing languages are hard to read, I've designed Big Pyth, which is both easily readable and easily translatable to Pyth. The linked file translates an input stream of Big Pyth to Pyth. Each whitespace-separated Big Pyth token corresponds to a Pyth token, either a character or a . followed by a character. The exceptions are the implicit tokens, which are implicit in the Pyth code.

I want to see how good an explanatory format Big Pyth is, so I'm not going to give any other explanation. Ask me if you want something explained, however.

answered Dec 30, 2016 at 13:46
\$\endgroup\$
0
1
\$\begingroup\$

Vyxal, 5 bytes

Þ√Ṙṅ§

Try it Online!

Header converts it into a single character matrix which is a valid input form.

answered Feb 14, 2024 at 13:25
\$\endgroup\$
0
\$\begingroup\$

JavaScript (ES6), 140 bytes

a=>[...Array(m=(h=a.length)<(w=a[0].length)?h:w)].map((_,i)=>[...Array(h+w-1)].map((_,j)=>(a[x=i+h-m-(++j>w&&j-w)]||``)[x+j-h]||` `).join``)

Takes input and output as arrays of strings. Also accepts a two-dimensional character array input, and save 7 bytes if a two-dimensional character array output is acceptable. Explanation: The height of the result m is the minimum of the height h and width w of the original array, while the width is simply one less than the sum of the height and width of the original array. The source row for the characters on the main portion of the result come directly from the appropriate row of the original array, counting up from the bottom, while on the extra portion of the result the source row moves up one row for each additional column. The source column for both halves of the result turns out to be equal to the destination column moved one column left for each source row above the bottom.

answered Dec 27, 2016 at 11:47
\$\endgroup\$
0
\$\begingroup\$

Octave, 57 bytes

@(A){B=spdiags(A),C=B>0,D=' '(C+1),D(sort(C))=B(C),D}{5}
answered Dec 27, 2016 at 13:29
\$\endgroup\$
0
\$\begingroup\$

Python 3, 247 bytes

def a(s):
 s=s.split('\n')
 for i,l in enumerate(s):r=len(s)-i-1;s[i]=' '*r+l+' '*(len(s)-r-1)
 print(*[''.join(i) for i in list(zip(*[''.join(a).rstrip([::-1].ljust(min(len(s),len(s[0])))for a in zip(*[list(i)for i in s])]))[::-1]],sep='\n')`
answered Dec 30, 2016 at 11:04
\$\endgroup\$
1
  • \$\begingroup\$ Useless whitespace at join(i) for. \$\endgroup\$ Commented Dec 30, 2016 at 13:48
0
\$\begingroup\$

Python 2, 150 bytes

def f(l):w=len(l[0]);h=len(l);J=''.join;R=range;print'\n'.join(map(J,zip(*['%%-%ds'%h%J(l[h+~i][j-i]for i in R(h)if-w<i-j<1)for j in R(h-~w)]))[::-1])

Takes input as list of strings.

answered Dec 30, 2016 at 12:47
\$\endgroup\$
0
\$\begingroup\$

Clojure, 194 bytes

Implemented the hard way by grouping characters to G and then generating lines.

#(let[n(count %)m(count(% 0))G(group-by first(for[i(range n)j(range m)][(min(- n i)(- m j))((% i)j)]))](apply str(flatten(for[k(reverse(sort(keys G)))][(repeat(dec k)" ")(map last(G k))"\n"]))))

Takes input as a vec of vecs like [[\a \b \c \d] [1円 2円 3円 4円] [\W \X \Y \Z]]. Example:

(def f #( ... ))
(print (str "\n" (f (mapv vec(re-seq #".+" "abcd\n1234\nWXYZ")))))
 ab
 c123
d4WXYZ
answered Jan 8, 2017 at 14:13
\$\endgroup\$

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.