28
\$\begingroup\$

EDIT I modified the wording of the rules to make some things which were implicit more explicit. I also added some emphasis to clear up some points of apparent confusion, and explicitly defined the option of making a standalone program instead of a function.

The goal here is to make a function that takes a text file (or string) and transposes it so that lines become columns and vice versa.

Example:

I am a text.
Transpose me.
Can you do it?

Results in:

ITC
 ra
aan
mn
 sy
apo
 ou
ts
eed
x o
tm
.ei
 .t
  ?

The rules:

  • You are allowed to assume that the only whitespace characters used are " " and "\n" and that there is no trailing whitespace on any line.
  • You may assume that the file is ASCII. Which endline marker you want to use is up to you.(CRLF or LF). It must work correctly on the example, but it should also work on any input that satisfies the above assumptions.
  • You might have to insert spaces (as in the example) where there were none in order to keep the columns in line.
  • Your result must not have trailing whitespace on any line.
  • The final newline character(for the last line) is optional.
  • It should be either a function or a complete program. If your function accepts a string, then it should return the results as a string. If it accepts a filename, then you return the name of the file where you saved the result. You are additionally allowed to write a complete program that accepts input from STDIN and outputs the correct result to STDOUT; if you do this, you must not output anything to STDERR.
  • Shortest procedure wins, but I will upvote any answer I like.

Based on the rules, the output on the example is either 53 or 52 bytes long (for LF newlines) depending on whether the final newline is included or not.

Note: It is not a specific requirement, but if your function, when run twice successively is not identical to the original(the final newline might be differ, and any empty lines at the end of the file will be deleted), then you are probably breaking one of the rules.

\$\endgroup\$
11
  • \$\begingroup\$ I decided to remove the prohibition on language built-ins. \$\endgroup\$ Jan 3, 2014 at 13:27
  • \$\begingroup\$ I edited to clarify the trailing whitespace condition. \$\endgroup\$ Jan 3, 2014 at 14:16
  • \$\begingroup\$ Are you asking for a function? Is it acceptable to accept a string from STDIN and print the correct output to STDOUT? \$\endgroup\$
    – Justin
    Jan 3, 2014 at 22:56
  • \$\begingroup\$ @Quincunx Yes, I am accepting that as a "function".I will alter the rules to be explicit on that point. \$\endgroup\$ Jan 4, 2014 at 12:30
  • \$\begingroup\$ The text transpose function cannot be an involution unless you allow for trailing ws. Example: "a*c\ndef\n" ->TT-> "a*\ncd\nef\n" ~ "a\ncd\nef\n" ->TT-> "acd\nef\n", where *=ws \$\endgroup\$ Mar 19, 2014 at 5:28

46 Answers 46

1
2
1
\$\begingroup\$

Python 2, 87 101 bytes

lambda s:T('\n'.join(map(T,map(''.join,zip(*[t.ljust(len(s))for t in s.split('\n')])))))
T=str.rstrip

Try it online!

\$\endgroup\$
4
  • \$\begingroup\$ Unfortunately Your result must not have trailing whitespace on any line. Also it seems to print a lot of extra newlines. \$\endgroup\$
    – Jo King
    Jul 30, 2018 at 7:32
  • \$\begingroup\$ @Jo King: Thx - My new toy did not work here! \$\endgroup\$
    – Chas Brown
    Jul 30, 2018 at 7:44
  • \$\begingroup\$ This still has trailing whitespace on some lines for example \$\endgroup\$
    – Jo King
    Jul 30, 2018 at 7:46
  • \$\begingroup\$ @Jo King: Ah yes. Fixed now. \$\endgroup\$
    – Chas Brown
    Jul 30, 2018 at 7:59
1
\$\begingroup\$

05AB1E, 6 bytes

ζεðÜ}»

Try it online.
Try it when taking the output as input-list again.

Explanation:

ζ         # Zip the input-list, swapping rows and columns
 ε  }     # For-each:
  ðÜ      #  Remove trailing spaces
     »    # Join the resulting list by new-lines (and output implicitly)
\$\endgroup\$
1
\$\begingroup\$

MATL, 5 bytes

!Z{Zv

Try it on MATL Online

Input is taken implicitly, and conveniently, the shorter lines get spaces added to them by the environment to make them all equal in length.

! - transpose

Z{ - Convert to cell array (since we'll need to hold arrays of different lengths after the next step)

Zv - deblank i.e. remove the trailing spaces

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

Octave, 35 29 bytes

@(s)strjoin(cellstr(s'),'\n')

Try it online!

(-1 byte thanks to Luis Mendo, -5 bytes thanks to strjoin from this SO answer)

\$\endgroup\$
2
  • \$\begingroup\$ You can remove the .. Best practices go out of the window in code golf :-P \$\endgroup\$
    – Luis Mendo
    Jul 31, 2018 at 15:08
  • \$\begingroup\$ @LuisMendo Ha, I didn't even realize I'd added the ., automatic muscle memory. \$\endgroup\$
    – Sundar R
    Jul 31, 2018 at 15:12
1
\$\begingroup\$

MATLAB: 24 42 29 bytes

@(s)deblank(string(char(s)'))

Usage

s=["I am a text.";"Transpose me";"Can you do it?"];
@(s)deblank(string(char(s)'))
ans(s)

Output

ans =

  14×3 char array

    'ITC'
    ' ra'
    'aan'
    'mn'
    ' sy'
    'apo'
    ' ou'
    'ts'
    'eed'
    'x o'
    'tm'
    '.ei'
    '  t'
    '  ?'

Might be cheating here, as it's hard (as far as I can see) to get a string with newlines into MATLAB without using an array, so I went ahead and used an array for the input. Other than that, it does what it says on the tin - turns the string into a matrix of chars, transposes it and trims the whitespace.

Edit: Changed (and lengthened) the program as I didn't see the requirement for whitespace to be trimmed.

Edit: -13 bytes thanks to sundar.

\$\endgroup\$
3
  • \$\begingroup\$ "Your result must not have trailing whitespace on any line." \$\endgroup\$ Jul 30, 2018 at 9:04
  • \$\begingroup\$ You don't need to include the f= in the byte count. And, you can probably shorten transpose(char(s)) to char(s)' (the single quote operator acts as a transpose here). \$\endgroup\$
    – Sundar R
    Jul 31, 2018 at 14:58
  • \$\begingroup\$ @sundar You're right! I use the single quote operator all the time but for some reason it totally slipped my mind while golfing... how annoying. \$\endgroup\$ Jul 31, 2018 at 15:29
1
\$\begingroup\$

JavaScript, 102 100 bytes

q=>[...q].reduce((r,e,j)=>(y=w.map((e,i)=>w[i][j]||" ").join``.trimEnd())?r+y+`
`:r,"",w=q.split`
`)

Run it here:

f = q=>[...q].reduce((r,e,j)=>(y=w.map((e,i)=>w[i][j]||" ").join``.trimEnd())?r+y+`
`:r,"",w=q.split`
`);

console.log(f(`I am a text.
Transpose me.
Can you do it?`));

\$\endgroup\$
5
  • \$\begingroup\$ Seems like there is still potential to golf this; a lot of big names and movable snippets \$\endgroup\$
    – MattH
    Jul 31, 2018 at 17:08
  • \$\begingroup\$ Using the same basic idea, I was able to get 92 by replacing reduce with map then filter then join(sounds longer, but you save the ternary, an assignment and some parens) \$\endgroup\$ Aug 1, 2018 at 10:06
  • \$\begingroup\$ without the string parameter golfing it looks like this: q=>[...q].map((x,i)=>w.map(x=>x[i]||" ").join("").trimEnd(),w=q.split("\n")).filter(x=>x).join("\n") \$\endgroup\$ Aug 1, 2018 at 10:10
  • \$\begingroup\$ Nevermind, I realized that will delete empty lines \$\endgroup\$ Aug 1, 2018 at 11:54
  • \$\begingroup\$ You've made me realize my solution incorrectly handles empty lines. Regardless, thanks for your solution. \$\endgroup\$
    – MattH
    Aug 1, 2018 at 14:08
1
\$\begingroup\$

C (MinGW), 272 262 259 254 234 229 228 bytes

-15 bytes thanks to ceilingcat

The TiO link requires the string.h include, but MinGW does not.

n,a,i,j;*f(int*s){char*p,**L=a=n=i=0,*r;for(;p=strtok(L?0:s,"\n");j>a?a=j:0)j=strlen((L=realloc(L,++n*8))[n-1]=p);for(p=r=calloc(n+1,a+1);i<a;i++,*p++=10){for(j=0;j<n;j++)*p++=i<strlen(L[j])?L[j][i]:32;while(p[-1]==32)p--;}s=r;}

Try it online!

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

PHP 227 217

Here's my attempt:

function f($s){$p=array_map;$s=$p(str_split,explode("
",$s));foreach($s as&$l)$l=array_pad($l,max($p(count,$s)),' ');array_unshift($s,null);foreach(call_user_func_array($p,$s)as$l)$r.=rtrim(implode($l))."
";return$r;}

Ungolfed:

<?php
function f($s) {
    $s=array_map(str_split, explode("\n",$s));
    foreach($s as &$l)
        $l=array_pad($l, max(array_map(count, $s)),' ');
    array_unshift($s, null);
    foreach(call_user_func_array(array_map, $s)as$l)
        $r.=rtrim(implode($l))."\n";
    return $r;
    }
$s="I am a text.
Transpose me.
Can you do it?";
echo f($s);
echo strlen(f($s));
\$\endgroup\$
0
\$\begingroup\$

Haskell: 191 chars

import Data.List
h [] = ' '
h (x:_) = x
t [] = []
t ([]:x) = t (" ":x)
t ((x:y):z) = takeWhile (any (/= ' ')).map (dropWhileEnd (== ' '))$(x:map h z):t (y:[s |(_:s)<-z])
m = (unlines.t.lines)
\$\endgroup\$
1
  • \$\begingroup\$ It's usually good to add some explanatory text. It helps those who don't know the language to decide to vote you up. :) \$\endgroup\$ Jan 6, 2014 at 15:37
0
\$\begingroup\$

JavaScript, 177 173 bytes

s=>{l=s.split`
`.sort((a,b)=>b.length-a.length)[0];for(i=0,t=[];i<l.length;i++){t[i]=s.split`
`.map(i=>i+" ".repeat(l.length-i.length)).map(j=>j[i]).join``}return t.join`
`}

s=>{l=s.split`\n`.sort((a,b)=>b.length-a.length)[0];for(i=0,t=[];i<l.length;i++){t[i]=s.split`\n`.map(i=>i+" ".repeat(l.length-i.length)).map(j=>j[i]).join``;}return t.join`\n`}

If you can help me shorten this up, please do so.

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

PHP, 95+0 108+1 110 bytes

foreach($input as $s)for($y=0;~$c=$s[$y];)$r[$y++].=$c>"
"?$c:" ";echo rtrim(join("
",array_map(rtrim,$r)));

takes input from STDIN; breaks at the first empty line. Run with -nr or try it online.

Still trying to find something shorter than the additional rtrim to get rid of the second newline.

\$\endgroup\$
8
  • \$\begingroup\$ In general, I like this answer, but there are a number of issues; read the spec: "Your result must not have trailing whitespace on any line". Also, the rules for I/O are slightly ambiguous, but this isn't technically one of the allowed options, and this definitely isn't a complete program since you have to invoke the interpreter with non-default options. \$\endgroup\$ Dec 2, 2017 at 14:03
  • \$\begingroup\$ Unless I am more rusty at PHP than I thought, the way you are calling file(f) will result in a warning being printed to stderr, which since you are using stdout as your output method is also not allowed. If there is a specific version of the PHP interpreter that no longer has this behviour(it used to IIRC), then please specify or correct me if I am wrong. \$\endgroup\$ Dec 2, 2017 at 14:06
  • \$\begingroup\$ The simplest correction to everything but the endline issue that I can think of at the moment results in 8 additional characters. The simplest solution for the endline issue I can think of adds an extra 7. That still makes it by far the shortest PHP entry. \$\endgroup\$ Dec 2, 2017 at 14:10
  • \$\begingroup\$ @TimSeguine 1) -n (no config file) tells the compiler to run with the default options. 2) The rules are ridiculous, but I´ll look into resolving the "issues" anyway. \$\endgroup\$
    – Titus
    Dec 2, 2017 at 15:15
  • 1
    \$\begingroup\$ I have a few ideas for how to shave characters, but I don't have time to try any out for now. What I see is no reason to use $argn instead of STDIN for the purpose of the challenge. And is the $x=> important? looks like just a waste of 4 chars to me. If you are curious, the rules were an attempt at leveling the playing field with code golfing specific languages. How successful I was in that goal is debatable. \$\endgroup\$ Dec 4, 2017 at 14:26
0
\$\begingroup\$

Perl 5, 81 bytes

chomp(@a=<>);say((join"",map{(substr$_,0,1,"")||$"}@a)=~s/\s+$//r)while"@a"=~/\S/

Try it online!

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

Lua, 205 bytes

L={}C=0 R=io.read I=R()while I~=""do L[C]=I C=C+1 I=R()end M=0 for i=0,C-1,1 do if#L[i]>M then M=#L[i]end end for i=1,M,1 do for j=0,C-1,1 do io.write(L[j]:sub(i,i)==""and" "or L[j]:sub(i,i))end print()end

Try it online!

Ungolfed

lines={}
count=0
R=io.read
input=R()

-- reads input in until an empty line is found
-- lines are added to the lines table
while input~="" do
    lines[count]=input
    count=count+1;
    input=R()
end

-- find the length of the longest string
max_len=0
for i=0,count-1,1 do
    if #lines[i]>max_len then
        max_len=#lines[i]
    end
end

-- loop through each character of each string
for i=1,max_len,1 do
    for j=0,count-1,1 do
        -- print the string's next character
        -- or a space if there is not another character
        if lines[j]:sub(i,i)=="" then--this if statement is golfed into a
            io.write(" ")            --pseudo-ternary statement in the golfed version
        else
            io.write(lines[j]:sub(i,i))
        end
    end
    print()
end
\$\endgroup\$
0
\$\begingroup\$

Pyth, 2 bytes

.t

Try it here!

Performs the built in transpose function on an input list, outputting a list of lines.


Pyth, 7 bytes

V.t.zdN

Try it here!

The above program, modified to use the input and output format specified in the challenge.

\$\endgroup\$
1
  • \$\begingroup\$ From the spec: "Your result must not have trailing whitespace on any line." - it caught me out as well. \$\endgroup\$
    – Shaggy
    Jul 19, 2018 at 13:45
0
\$\begingroup\$

Excel VBA, 154 bytes

Takes input from [A1] and outputs to the console.

x=Split([A1],vbLf):u=UBound(x):For i=0To u:l=Len(x(u)):m=IIf(m>l,m,l):Next:For i=1To m:For j=0To u:s=s+Mid(x(j)&String(m,32),i,1):Next:?RTrim(s):s="":Next

Ungolfed

x=Split([A1],vbLf)              ''  Split input by lines
u=UBound(x)                     ''  Get number of lines
For i=0To u                     ''  Iterate over lines
l=Len(x(u))                     ''  Get length of line `i`
m=IIf(m>l,m,l)                  ''  Compare to max length; Store Max
Next                            ''  Loop
For i=1To m                     ''  Iterate over chars in line
For j=0To u                     ''  Iterate over lines
s=s+Mid(x(j)&String(m,32),i,1)  ''  Append `i`th char of `j`th line to `s` 
Next                            ''  Loop
?RTrim(s)                       ''  Remove right whitespace, print
s=""                            ''  Reset `s`
Next                            ''  Loop
\$\endgroup\$
0
\$\begingroup\$

K (oK), 43 bytes

Solution:

{"\n"/{(-+/&\32=|x)_x}@'+(|/#:'x)$x:"\n"\x}

Try it online!

Explanation:

Break on newlines, pad lines to same lengths, transpose, trim trailing whitespace and join on newlines. Feels like there has to be an easier way...

{"\n"/{(-+/&\32=|x)_x}@'+(|/#:'x)$x:"\n"\x} / the solution
{                                         } / lambda
                                         x  / input x
                                    "\n"\   / split (\) on "\n"
                                  x:        / save as x
                                 $          / pad right with left
                         (      )           / do this together
                            #:'x            / count (#:) each (') x
                          |/                / max
                        +                   / transpose
      {              }@'                    / apply (@) lambda to each (')
                    x                       / input x
                   _                        / drop
       (          )                         / do this together
                |x                          / reverse (|) x
             32=                            / equal to ASCII 32 aka " "
           &\                               / min
         +/                                 / sum
        -                                   / negate
 "\n"/                                      / join (/) on "\n"
\$\endgroup\$
1
  • \$\begingroup\$ A couple bytes can be saved by using {(-(|^x)?0)_x} to trim the trailing whitespace. \$\endgroup\$
    – coltim
    Dec 9, 2020 at 15:00
1
2

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.