33
\$\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\$ Commented Jan 3, 2014 at 13:27
  • \$\begingroup\$ I edited to clarify the trailing whitespace condition. \$\endgroup\$ Commented 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
    Commented 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\$ Commented 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\$ Commented Mar 19, 2014 at 5:28

51 Answers 51

1
2
1
\$\begingroup\$

K, 56

This should meet the spec now.

Accepts a string, returns a string.

{`/:{$[" "=*|x;|(+/&\" "=|x)_|x;x]}'x@'/:!max@#:'x:`\:x}

.

k)f:{`/:{$[" "=*|x;|(+/&\" "=|x)_|x;x]}'x@'/:!max@#:'x:`\:x}
k)f"I am a text.\nTranspose me.\nCan you do it?"
"ITC\n ra\naan\nmn\n sy\napo\n ou\nts\need\nx o\ntm\n.ei\n .t\n  ?\n"
k)f f"I am a text.\nTranspose me.\nCan you do it?"
"I am a text.\nTranspose me.\nCan you do it?\n"
\$\endgroup\$
5
  • \$\begingroup\$ The output appears to be an array of strings? \$\endgroup\$ Commented Mar 19, 2014 at 17:02
  • \$\begingroup\$ @Tim It is. If you want a single string then add three chars. {`/:x@'/:!max@#:'x:`\:x} for 26. \$\endgroup\$
    – tmartin
    Commented Mar 19, 2014 at 17:39
  • \$\begingroup\$ You also have a problem with trailing whitespace. And "If it accepts a filename, then you return the name of the file where you saved the result." You need to return output in the same manner you accept input. \$\endgroup\$ Commented Mar 20, 2014 at 10:18
  • \$\begingroup\$ @Tim should be fixed now. Kills my bytecount though \$\endgroup\$
    – tmartin
    Commented Mar 20, 2014 at 12:09
  • \$\begingroup\$ I suspected it might :( , but a spec is a spec. \$\endgroup\$ Commented Mar 20, 2014 at 12:13
1
\$\begingroup\$

Groovy, 98 chars

{i->o=[].withDefault{''};i.readLines().each{it.toList().eachWithIndex{c,d->o[d]+=c}};o.join('\n')}

online

ungolfed:

{i->
o=[].withDefault{''};//create list with empty string as default value 
i.readLines()
.each{
    it.toList() //split every line to characters
    .eachWithIndex{ 
        c,d->o[d]+=c //append to string from list with right index
    }
};
o.join('\n')}//join list with newlines
}
\$\endgroup\$
1
\$\begingroup\$

Pyth, 11 bytes

# aYcw1;.tY

Try it online!

Takes input as a string, outputs a list of lists

Pyth, 25 bytes

# aYcw1=+Z1;jbcj"".n.tY)Z

Takes input as a string, outputs a string.

Try it online!

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

J, 28 26 Bytes

Saved 2 bytes thanks to frownyfrog

t=.,@:(,&LF"1)@|:@:>@cutLF

Takes a string, returns a string. I'm not sure if there's a shorter version of the 'cutopen' function verb that I could use.

There's also the shorter

t=.|:@:>@cutLF

But I'm not sure it falls within the OP's guidelines, as it returns an array of characters.

How it works:

                     cutLF   | Splits the input on new lines and boxes them
                    @        | Composes verbs (as does @:, but they're not equal)
                   >         | Unboxes this, forming an array of the lines
                 @:          |
               |:            | Transposes the array
      (      )@              |
       ,&LF                  | Appends a new line...
           "1                | To each row of the array
    @:                       |
   ,                         | Flatten the result
t=.                          | Assign this verb to t

The other version works the same, but doesn't convert the transposed array to a properly formatted string.

Examples:

NB. Define a multi-line string

    text =: 0 : 0
I am a text.
Transpose me.
Can you do it?
)

    t text
ITC
 ra
aan
mn    NB. There's whitespace after the 'n' here, but I assume it doesn't count as trailing since it's part of the original string
 sy
apo
 ou
ts 
eed
x o
tm 
.ei
 .t
  ?

    t t text
I am a text.     NB. Again, whitespace here, but it's part of the argument of the second 't' (added by the first 't' to keep columns straight)
Transpose me. 
Can you do it?
\$\endgroup\$
2
  • \$\begingroup\$ I would use cutLF. \$\endgroup\$
    – FrownyFrog
    Commented Dec 6, 2017 at 3:56
  • 1
    \$\begingroup\$ Save 1 character with 0|:>@cutLF \$\endgroup\$
    – FrownyFrog
    Commented Dec 6, 2017 at 4:10
1
\$\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\$
1
\$\begingroup\$

Lua, 203 189 bytes

t={{}}i=1m=0(...):gsub(".",function(c)n=#t[i]if c=="\n"then i=i+1t[i]={}else t[i][n+1]=c end m=m<=n and n+1or m end)
for x=1,m do for p=1,i do io.write(t[p][x]or" ")end _=m<=x or print()end

Try it online!

I saw another Lua solution here, but I don't think there's a problem with posting 2 solutions on the same language. If there is, tell me :)

\$\endgroup\$
5
  • 1
    \$\begingroup\$ There's nothing wrong with multiple answers in the same language. Even identical answers are allowed to an extent (though it's encouraged to at least check if you're posting the a similar solution) \$\endgroup\$
    – Jo King
    Commented Jul 25, 2018 at 6:56
  • \$\begingroup\$ Unfortunately Your result must not have trailing whitespace on any line. \$\endgroup\$
    – Jo King
    Commented Jul 30, 2018 at 7:33
  • \$\begingroup\$ But I can't see trailing whitespaces on the output of my code. There's no spaces after the line ends and no blank line at the end. \$\endgroup\$
    – Visckmart
    Commented Jul 30, 2018 at 7:35
  • \$\begingroup\$ The part that seems to catch people out is on any line. e.g. This has extra whitespace on the second line \$\endgroup\$
    – Jo King
    Commented Jul 30, 2018 at 7:40
  • \$\begingroup\$ Ohhh now I got it! Sorry. I'll try to make it work as soon as I have time. I think the problem was that there's only 1 example test and I thought that would be the "stress" test hahah But ok, thanks for telling me :) \$\endgroup\$
    – Visckmart
    Commented Jul 30, 2018 at 7:44
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
    Commented Jul 30, 2018 at 7:32
  • \$\begingroup\$ @Jo King: Thx - My new toy did not work here! \$\endgroup\$
    – Chas Brown
    Commented Jul 30, 2018 at 7:44
  • \$\begingroup\$ This still has trailing whitespace on some lines for example \$\endgroup\$
    – Jo King
    Commented Jul 30, 2018 at 7:46
  • \$\begingroup\$ @Jo King: Ah yes. Fixed now. \$\endgroup\$
    – Chas Brown
    Commented Jul 30, 2018 at 7:59
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
    Commented Jul 31, 2018 at 15:08
  • \$\begingroup\$ @LuisMendo Ha, I didn't even realize I'd added the ., automatic muscle memory. \$\endgroup\$
    – Sundar R
    Commented 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\$ Commented 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
    Commented 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\$ Commented 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
    Commented 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\$ Commented 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\$ Commented Aug 1, 2018 at 10:10
  • \$\begingroup\$ Nevermind, I realized that will delete empty lines \$\endgroup\$ Commented 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
    Commented 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
1
\$\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
    Commented Dec 9, 2020 at 15:00
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\$

Setanta, 191 190 bytes

gniomh(s){s=roinn@s("
")t:=0u:=""le i idir(0,fad@s)t=uas(t,fad(s[i]))le i idir(0,t){le j idir(0,fad@s)u+=(i<fad(s[j])&s[j][i])|" "nuair-a u!=""&u[-1]==" " u=cuid@u(0,fad@u-1)u+="
"}toradh u}

try-setanta.ie link

\$\endgroup\$
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\$ Commented 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\$ Commented 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\$ Commented 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\$ Commented 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
    Commented 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\$ Commented 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
    Commented Jul 19, 2018 at 13:45
1
2

Your Answer

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

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