34
\$\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\$ 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

6
\$\begingroup\$

Bash+coreutils+sed, 83

eval paste `sed 's/.*/<(fold -w1<<<"&")/'`|expand -t2|sed 's/\(.\) /\1/g;s/ \+$//' 

fold and paste do the important work. The rest is just formatting.

Accepts input from stdin and outputs to stdout:

$ < tr.txt ./transposefile.sh ITC ra aan mn sy apo ou ts eed x o tm .ei .t ? $ < tr.txt ./transposefile.sh | ./transposefile.sh I am a text. Transpose me.? Can you do it $ 
\$\endgroup\$
4
  • \$\begingroup\$ You appear to be breaking the rule "Your result must not have trailing whitespace on any line." \$\endgroup\$ Commented Mar 19, 2014 at 9:56
  • \$\begingroup\$ @TimSeguine Oops I missed that one. I just fixed it in the latest edit. \$\endgroup\$ Commented Mar 19, 2014 at 16:56
  • \$\begingroup\$ Great answer. Try it online! \$\endgroup\$ Commented Mar 24, 2021 at 5:14
  • \$\begingroup\$ It's actually 82 bytes, according to TIO \$\endgroup\$ Commented Jul 3, 2024 at 12:08
5
\$\begingroup\$

Ruby: 88 characters

(Posted because it's shorter then the other Ruby solutions. Not checked whether my code introduces anything new compared to those. If you already posted a Ruby solution and you feel this is mostly a copy of yours, please comment and I will retire my answer.)

f=->t{l=t.split$/;r=[""]*m=l.map(&:size).max;l.map{|l|m.times{|i|r[i]+=l[i]||" "}};r*$/} 

Attempt This Online!

Sample run:

irb(main):001:0> f=->t{l=t.split$/;r=[""]*m=l.map(&:size).max;l.map{|l|m.times{|i|r[i]+=l[i]||" "}};r*$/} => #<Proc:0x99a9e68@(irb):1 (lambda)> irb(main):002:0> sample='I am a text. irb(main):003:0' Transpose me. irb(main):004:0' Can you do it?' => "I am a text.\nTranspose me.\nCan you do it?" irb(main):005:0> puts f[sample] ITC ra aan mn sy apo ou ts eed x o tm .ei .t ? => nil irb(main):006:0> puts f[f[sample]] I am a text. Transpose me. Can you do it? => nil 
\$\endgroup\$
0
5
\$\begingroup\$

Perl 5 + -plF -M5.10.0, 22 bytes

Utilises ANSI escape sequences and unprintables.

$"="..";$_=".[1;$.H@F"

Try it online!

Explanation

This code first changes the list separator ($") value to be a form-feed and a backspace, then we set the implicitly printed variable $_ to be a string that starts with the ANSI escape sequence for 'start printing at line 1 column $. (where $. is the current line of text: \x1b1;$.H) and interpolates the list @F (which is a list of all the characters on that line, populated by autosplit (-a, implied by -F) with an empty split pattern (-F)) which places the contents of $" in between each item, moving the cursor vertically down instead of continuing output after the previous character.

\$\endgroup\$
1
  • 1
    \$\begingroup\$ Oh my god, the sheer horror! I love it! \$\endgroup\$ Commented Aug 6, 2018 at 12:37
5
\$\begingroup\$

Zsh +coreutils, 139 110 109 105 95 55 bytes

for i ({1..`wc -L<a`})cut -c$i a|rs -eg0|sed 's/ *$//' 

Try it online!

Assumes input file a has lines of varying length. Pads the lines with spaces Slices, reshapes, and trims trailing spaces.

`wc -L<a` # get the longest line of 𝐚̲ for i ()cut -c$i a # take vertical slices of 𝐚̲ at each $i |rs -eg0|sed 's/ *$//' # reshape and remove trailing spaces 

Naïve solution (TIO): for i ({1..`wc -L<a`})cut -c $i a|tr -d \\n&&echo
95b 105b 109b 110b 139b

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

J (31 40)

f=:3 :';(,&LF@dlb&.|.)&.><"1|:>LF cut y' 

This is a function that takes a string, and returns a string (i.e. a character vector with linefeeds inserted in the right places, and not a matrix.)

Edit: no trailing whitespace on any line.

Test:

 f=:3 :';(,&LF@dlb&.|.)&.><"1|:>LF cut y' string=:stdin'' I am a text. Transpose me. Can you do it? ^D $string 42 $f string 53 f string ITC ra aan mn sy apo ou ts eed x o tm .ei .t ? 
\$\endgroup\$
10
  • \$\begingroup\$ I hope you noticed I removed the prohibition for built-ins. \$\endgroup\$ Commented Jan 3, 2014 at 13:43
  • \$\begingroup\$ @Tim: Yes, otherwise I wouldn't have posted this. \$\endgroup\$ Commented Jan 3, 2014 at 13:44
  • \$\begingroup\$ Is the trailing whitespace rule written unclearly? You seem to have more characters than I expected. \$\endgroup\$ Commented Jan 3, 2014 at 13:55
  • \$\begingroup\$ How many characters should I have? The last characters on the string are ?\n. \$\endgroup\$ Commented Jan 3, 2014 at 14:02
  • 1
    \$\begingroup\$ @Tim: I could only get it to 44 in APL. Main reason is that APL doesn't provide either cut or dlb by default and writing them myself takes a bunch of characters even in APL. \$\endgroup\$ Commented Jan 5, 2014 at 0:29
4
\$\begingroup\$

Ruby 111

Golfed:

def f t;s=t.lines;s.map{|l|l.chomp.ljust(s.map(&:size).max).chars}.transpose.map{|l|l.join.rstrip+?\n}.join;end 

Ungolfed:

def transpose_text(text) max_length = text.lines.map(&:size).max text.lines.map do |line| line.chomp.ljust(max_length).chars end.transpose.map do |chars| chars.join.rstrip + "\n" end.join end 

Ruby has an array transpose function, so this simply pads the lines out, turns them into an array of characters, uses Ruby's Array#transpose function, then turns the array of characters back into lines.

Golfing it was simply using single-character identifiers, removing spaces, using a temporary for text.lines, and putting the calculation for max_length inline (there are no points for efficiency).

\$\endgroup\$
5
  • \$\begingroup\$ Nice. You can strip out one more character by replacing "\n" with ?\n. \$\endgroup\$ Commented Jan 3, 2014 at 21:04
  • \$\begingroup\$ Also, the .to_a is superfluous. You can gain another 5 characters there. \$\endgroup\$ Commented Jan 3, 2014 at 21:43
  • \$\begingroup\$ @O-I Thanks, I owe you six characters. I dashed this off at work, which uses 1.9.3. The to_a is required in 1.9.3, but not in 2.0. \$\endgroup\$ Commented Jan 3, 2014 at 22:29
  • \$\begingroup\$ I see. Good to know. Consider us even for showing me a few String methods in Ruby I should be using more often. Cheers! \$\endgroup\$ Commented Jan 4, 2014 at 0:19
  • 2
    \$\begingroup\$ Some of the code golf challenges have renewed my interest in learning ruby. \$\endgroup\$ Commented Jan 4, 2014 at 13:29
4
\$\begingroup\$

R, 171

function(e){p=strsplit x=t(plyr::rbind.fill.matrix(lapply(p(p(e,"\n")[[1]],""),t))) x[is.na(x)]=" " cat(apply(x,1,function(y)sub(" *$","",paste(y,collapse=""))),sep="\n")} 

Usage example:

text <- "I am a text. Transpose me. Can you do it?" (function(e){p=strsplit x=t(plyr::rbind.fill.matrix(lapply(p(p(e,"\n")[[1]],""),t))) x[is.na(x)]=" " cat(apply(x,1,function(y)sub(" *$","",paste(y,collapse=""))),sep="\n")})(text) ITC ra aan mn sy apo ou ts eed x o tm .ei .t ? 

Trailing whitespace is removed.

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

Python 2.7 (97 79 94 90)

EDIT: Missed the function requirement;

I'm fairly sure this will be improved on since I'm sort of a beginner here, but to start with;

c=lambda a:'\n'.join(''.join(y or' 'for y in x).rstrip()for x in map(None,*a.split('\n'))) 

The code uses a simple split to split the string into a vector of rows. It then uses map with a function value as None (the unity function) and the splat operator to transpose and pad the vector (similar functionality to zip_longest in Python3)

The rest of the code just maps None to space, trims and reassembles the matrix to a single string again.

>>> a = 'I am a text.\nTranspose me.\nCan you do it?' >>> c(a) 'ITC\n ra\naan\nmn\n sy\napo\n ou\nts\need\nx o\ntm\n.ei\n .t\n ?' >>> len("""c=lambda a:'\n'.join(''.join(y or' 'for y in x).rstrip()for x in map(None,*a.split('\n')))""") 88 # (+2 since `\n` is considered by `len` to be a single char) 
\$\endgroup\$
2
  • \$\begingroup\$ +1 you appear to be the shortest compliant python entry at the moment. \$\endgroup\$ Commented Jan 4, 2014 at 13:23
  • \$\begingroup\$ Nice use of map. I keep looking for a place to use that... and you just beat me to it. ;) \$\endgroup\$ Commented Jan 4, 2014 at 19:26
4
\$\begingroup\$

Uiua, 31 bytes

/$"_\n_"⍚⍜⇌(▽\↥≠@ .)⍉⬚@ ⊜∘≠@\n. 

Try it in the pad!

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

Japt, 6 5 bytes

Õmx1R 

Try it
Run it twice (returns original string)

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

C (278 bytes)

Edit: This actually breaks the rules, since it takes a filename in as an argument but writes to stdout. I'll edit it later to write to a file and then print the filename to stdout.

This is my first code golf ever, so have mercy. Some plain old C. Place the input in test.txt and let it run!

clang transpose.c -o transpose && ./transpose test.txt

#import <stdio.h> #import <stdlib.h> #import <string.h> #define BUFFER_SIZE 1024 #define MAX(A,B) ((A)>(B)?(A):(B)) int main(int argc, char **argv) { char line[BUFFER_SIZE]; FILE *f; int nLines, maxLen; f = fopen(argv[1], "r"); while(!feof(f) && fgets(line, BUFFER_SIZE, f)) { nLines++; maxLen = MAX(maxLen, strlen(line)); } fclose(f); for (int charPos = 0; charPos < maxLen; charPos++) { f = fopen(argv[1], "r"); for (int linePos = 0; linePos < nLines; linePos++) { fgets(line, BUFFER_SIZE, f); printf("%c", charPos < strlen(line) && line[charPos] != '\xA' ? line[charPos] : ' '); } printf("\n"); fclose(f); } return 0; } 

By using short variable names, removing gratuitous formatting, and allowing file handles to leak, and disabling all warnings this is reduced to 278 bytes. (Since this uses implicit imports, it may not link properly on all systems. Works on my machine!)

#import <stdio.h> int main(int C,char**V){char L[1024];int A,B,D,I,J,*F=fopen(V[1],"r");while(!feof(F)&&fgets(L,1024,F)){A++;D=strlen(L);B=B>D?B:D;}for(I=0;I<B;I++){F=fopen(V[1],"r");for(J=0;J<A;J++)fgets(L,1024,F)&&printf("%c",I<strlen(L)&&L[I]!='\n'?L[I]:' ');printf("\n");}} 
\$\endgroup\$
7
  • \$\begingroup\$ I think you can take advantage of implicit int to shorten some of your declarations, or is that illegal now? \$\endgroup\$ Commented Jan 3, 2014 at 15:51
  • \$\begingroup\$ Yeah, I'm using that in a later edit to not import stdlib.h or string.h. If I don't import stdio.h it segfaults on run. \$\endgroup\$ Commented Jan 3, 2014 at 15:59
  • \$\begingroup\$ To your edit comment on the rules: your other alternative is to accept input from stdin. I would consider that conforming as well. And also, I can't tell from a cursory glance: does it strip whitespace from the ends of lines in the transpose version? \$\endgroup\$ Commented Jan 3, 2014 at 16:09
  • \$\begingroup\$ Since I re-read the file multiple times to avoid storing in RAM, reading from stdio would probably be harder. :) I'm not sure what whitespace should be stripped. Right now I don't think it does any stripping at all, unfortunately. I'll have to work on that too. \$\endgroup\$ Commented Jan 3, 2014 at 16:18
  • \$\begingroup\$ You can declare A,B,D,I,J,*F as global variables, in order to avoid int keyword. Similarly, you can remove int from main declaration, and C argument. In C, int is optional in many places. \$\endgroup\$ Commented Jan 3, 2014 at 16:44
3
\$\begingroup\$

AutoHotkey 210

f(i){ StringSplit,o,i,`n m:=0 loop % o0 { a:=A_index if (t:=Strlen(p:=o%a%))>m m:=t StringSplit,l%a%,o%a% } loop % m { a:=A_index,n:="" loop % o0 n.=(j:=l%A_index%%a%)=""?" ":j s.=Rtrim(n," ") "`n" } return s } 

Test

text= ( I am a text. Transpose me. Can you do it? ) msgbox % f(text) 
\$\endgroup\$
1
  • \$\begingroup\$ I can't test this one, but it looks compliant \$\endgroup\$ Commented Jan 4, 2014 at 12:56
3
\$\begingroup\$

CJam, 32 25 bytes

CJam is newer than this challenge, so this answer is not eligible for being accepted.

Considerably shortened by user23013.

qN/_z,f{Se]}z{S+e`);e~N}% 

Test it here.

qN/ "Read input, split into lines."; _z, "Transpose, get length (find maximum line length)."; f{Se]} "Pad each line to that length with spaces."; z "Transpose."; { }% "Map this block onto each line in the result."; S+ "Add a space to ensure there's at least one."; e` "Run-length encode."; ); "Discard the trailing run of spaces."; e~ "Run-length decode"; N "Push a newline."; 
\$\endgroup\$
2
  • \$\begingroup\$ Eligible or not, it is a great late answer. Seems like the hardest part for this answer was dealing with the trailing spaces. \$\endgroup\$ Commented Apr 25, 2015 at 10:35
  • \$\begingroup\$ @TimSeguine Indeed. Without a built-in trimming operator, doing this manually in CJam is surprisingly cumbersome (user23013's suggestion already improved it considerably). \$\endgroup\$ Commented Apr 25, 2015 at 13:00
3
\$\begingroup\$

Retina, 40 bytes

P`.+ ~L0$`. L,$.%'vs,$.(x$%=),`.+ m` *$ 

Try it online!

Based on this program that I created to transpose any size of rectangle, which uses Leo's suggestion for transposing a rectangle of a known size.

Edit: Golfed more and no longer has trailing spaces on lines.

\$\endgroup\$
3
\$\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\$
3
\$\begingroup\$

R, 106 bytes

for(j in Map(substr,list(s<-scan(,"",sep="\n")),n<-1:max(nchar(s)),n))cat(ifelse(j==""," ",j),"\n",sep="") 

Attempt This Online!

I have chosen to write the complete program: it grabs the manual input and prints the result out.

The text is transformed to a list of characters vectors (puts together all the 1st letters, the 2nd etc.). This is done by mapping the substr function, and the list size corresponds to the longest textline. When there is not enough characters an empty character is produced (this is why I prefer to use substr instead of strsplit: there'll be no vector recycling!).

The program then iterates through this list and conditionally outputs the characters: instead of the empty one there will be a space, or the character itself otherwise; the newlines are added at the end of each vector.

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

K (ngn/k), 33 bytes

{"\n"/(|&\|^:)_'+(|/#'x)$x}@"\n"\ 

Try it online!

  • {...}@"\n"\ split (implicit) input on newlines, passing into lambda
    • +(|/#'x)$x right-pad each string to maximum length with spaces, then transpose
    • (|&\|^:)_' drop trailing spaces from each line
    • "\n"/ join with newlines and (implicitly) return
\$\endgroup\$
2
\$\begingroup\$

GolfScript, 51 chars

n%.{,}%$-1=" "*:y;{y+y,<}%zip{n\+0{;).32=}do}%((;\+ 

This is a first attempt; I suspect it can be improved. Most of the code is to comply with the padding and trailing space removal requirements — without them, just n%zip n* would suffice.

Ps. The following 46-character version will do the job for the given sample input, but will crash if any input column consists entirely of spaces:

n%.{,}%$-1=" "*:y;{y+y,<}%zip{0{;).32=}do]}%n* 

I assume that's enough to disqualify it, even if the challenge doesn't explicitly say so.

\$\endgroup\$
1
  • \$\begingroup\$ Your assumption is correct. It should work on any ASCII text under the assumptions allowed in the rules. \$\endgroup\$ Commented Jan 4, 2014 at 13:03
2
\$\begingroup\$

Ruby — 144 characters

Here's my first attempt, golfed:

def f t t.split(?\n).each{|l|l<<' 'until l.size==t.split(?\n).map(&:size).max}.map{|x|x.split('')}.transpose.map{|l|l.join.rstrip}.join(?/n) end 

For output, run puts f text where text is any multi-line string adhering to the rules above. The ungolfed version is below:

def text_transpose(text) lines = text.split(?\n) maxlen = lines.map(&:size).max lines.each { |line| line << ' ' until line.size == maxlen } .map { |line| line.split('') }.transpose .map { |char| char.join.rstrip }.join(?\n) end 

For a similar, but ultimately better solution in Ruby, check out Wayne Conrad's code above.

\$\endgroup\$
2
  • \$\begingroup\$ I didn't notice the transpose in your answer before I wrote mine. It doesn't seem quite kosher for me to have essentially rewritten your answer, only a little better. :( \$\endgroup\$ Commented Jan 4, 2014 at 17:07
  • 2
    \$\begingroup\$ I don't mind at all. You came up with your code independently and it's not a race. I definitely learned something from your solution. Had you held back because I used transpose, it's possible a better Ruby solution wouldn't have surfaced. One of things I love most about programming is the willingness to collaborate and cross-pollinate ideas. Till we meet again, kind sir. Cheers! \$\endgroup\$ Commented Jan 4, 2014 at 23:45
2
\$\begingroup\$

PHP 194

function x($a){$a.="\n";$s=strlen($a);$i=0;while($c<$s)if($a{$c}!="\n")$b[$i++].=$a{$c++};else{$c++;for(;$i<$s;$i++)$b[$i].=" ";$i=0;}ksort($b);return rtrim(implode("\n",array_map("trim",$b)));} 

Non-golfed:

function x($a) { $a.="\n"; $s=strlen($a); $i=0; while($c<$s) if($a{$c}!="\n") $b[$i++].=$a{$c++}; else{ $c++; for(;$i<$s;$i++) $b[$i].=" ";$i=0; } ksort($b); return rtrim(implode("\n",array_map("trim",$b))); } 

This is my first golfing attempt, so please be kind! Also, tips/suggestions would be greatly appreciated!

\$\endgroup\$
4
  • \$\begingroup\$ It's shorter than my php attempt. You can save two characters by gitting rid of the "s around "trim". php will give a warning, but it works just fine. \$\endgroup\$ Commented Jan 4, 2014 at 12:39
  • \$\begingroup\$ @TimSeguine Warnings output on screen though right? You'll have to use @ to suppress warnings. \$\endgroup\$ Commented May 5, 2016 at 13:42
  • \$\begingroup\$ @eric I haven't been active in a while so the opinions might have changed, but in the past it was deemed acceptable to output irrelevant data to standard error. \$\endgroup\$ Commented May 5, 2016 at 15:09
  • \$\begingroup\$ It's allowed? If that is true, then I didn't know that. \$\endgroup\$ Commented May 5, 2016 at 16:41
2
\$\begingroup\$

Haskell

import Data.List main = interact (unlines . transpose . lines) 

It was so short, I needed to add in white space...

\$\endgroup\$
3
  • \$\begingroup\$ I'm almost sure you can remove some of the whitespace here. But otherwise, great solution. \$\endgroup\$ Commented Jan 4, 2014 at 9:05
  • 3
    \$\begingroup\$ This doesn't quite work on my system. It's a bit hard to show in a comment, but if you run it twice you get I am a text..? Transpose met Can you do i. \$\endgroup\$ Commented Jan 4, 2014 at 10:42
  • \$\begingroup\$ Yeah, I am thinking maybe you are not padding the lines to keep the columns intact like the example does. Theorectally, the result of running the function twice should be the original string(with possibly the addition or removal of the final newline.) \$\endgroup\$ Commented Jan 4, 2014 at 12:33
2
\$\begingroup\$

MATHEMATICA 117 chars

t = "I am a text.\nTranspose me.\nCan you do it?"; f=(m=Length/@(f=Flatten[Characters/@StringSplit[#,"\n"],{{2},{1}}])//Max; StringJoin@@@(PadLeft[#,m," "]&/@f)//Column)& 
\$\endgroup\$
2
  • \$\begingroup\$ I can't test this one, so can you verify that it removes traling whitespace on the ends of lines? Also this doesn't appear(at first glance) to define a function, which the rules require. \$\endgroup\$ Commented Jan 4, 2014 at 12:54
  • \$\begingroup\$ hi @Tim, now it is a function f!.. tks \$\endgroup\$ Commented Jan 4, 2014 at 13:03
2
\$\begingroup\$

Perl (92+1)

reads stdin and writes to stdout. adding 1 to the score for say

@L=map[grep!/\n/,split//],<>;do{$_=join'',map shift@$_||$",@L;s/ +$//;say}while grep@$_>0,@L 
\$\endgroup\$
2
\$\begingroup\$

Bash, 124 bytes

D=`mktemp -d`;split -l1 - $D/;for F in $D/*;do grep -o . $F>$F+ done;paste $D/*+|sed -e's/\([^\t]\)\t/\1/g;s/\t/ /g;s/ *$//' 

It reads standard input and writes standard output. Try it:

echo $'I am a text.\nTranspose me.\nCan you do it?' | script.sh 

How it works:

  • split input into single lines (files in temporary directory $D)
  • split lines into single characters using grep (files *+)
  • layout characters side-by-side using paste (TAB-separated columns)
  • remove alignment TABs, replace filler TABs with BLANKs, trim using sed

Edit:

  • -9: Removed tidy-up code ;rm -r $D (thanks Tim)
  • -2: use + instead of _ as suffix and shorten ${F}_ to $F+
  • -3: remove prefix L from split result files
\$\endgroup\$
2
  • \$\begingroup\$ For the purposes of code golf, you don't necessarily have to be nice and clean up after yourself. You can leave off the rm bit from your character count. \$\endgroup\$ Commented Jan 5, 2014 at 20:15
  • \$\begingroup\$ Can't get this to work on TIO (no way I am running it locally!). Downvote I'm afraid \$\endgroup\$ Commented Jul 15, 2024 at 10:00
2
\$\begingroup\$

Javascript, 103

s=>[...s].map((_,i)=>s.split` `.map(b=>r+=b[q=b[i]||q,i]||' ',r=q='')&&r.replace(/ *$/,q?` `:q)).join`` 

Less golfed

s=>[...s].map( // we need 'i' ranging from 0 to the length of the longest input line // so we scan all the input string, that is surely longer // but we need to check that after some point the output must be empty (_, i) => ( r = '', // the current output row, starts empty q = '', // flag to check if we are beyond the longest line s.split('\n') // split in rows .map( b => ( // for each input row in b q = b[i] || q, // if there is a char at position i in b, i goes to q r += b[i] || ' ' // add to output the char at position i or a fill space ) ), q // if q is still '', we are beyond the longest input line ? r.replace(/ *$/,`\n`) // trim leading space and add newline : '' // no output ) ).join('') 

Test

F= s=>[...s].map((_,i)=>s.split` `.map(b=>r+=b[q=b[i]||q,i]||' ',r=q='')&&r.replace(/ *$/,q?` `:q)).join`` function go() { var text=I.value var output = F(text) O.textContent = output } go()
#I { width:50%; height:5em }
<textarea id=I>I am a text. Transpose me. Can you do it?</textarea><br> <button onclick='go()'>Transpose</button> <pre id=O></pre>

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

C++ (243 characters)

Here's a function that takes and returns a string.

I could've shaved a couple dozen chars, but decided to keep it as not-stupid code (runs fast, reads okay). Maybe I only decided to do that because this is my first code golf... I'm not hardcore enough yet :)

string f(string s){stringstream ss(s);vector<string> v;for(size_t i=0;getline(ss,s);++i){if(v.size() < s.size())v.resize(s.size());for(size_t j=0;j<s.size();++j){v[j].resize(i,' ');v[j].push_back(s[j]);}}s="";for(auto& i:v)s+=i+'\n';return s;} 

With formatting:

string f(string s) { stringstream ss(s); vector<string> v; for(size_t i = 0; getline(ss, s); ++i) { if(v.size() < s.size()) v.resize(s.size()); for(size_t j = 0; j < s.size(); ++j) { v[j].resize(i, ' '); v[j].push_back(s[j]); } } s = ""; for(auto& i : v) s += i + '\n'; return s; } 
\$\endgroup\$
3
  • \$\begingroup\$ I assume you use using namespace std;. \$\endgroup\$ Commented Jan 3, 2014 at 18:59
  • \$\begingroup\$ @xfix Not normally, but I did for this \$\endgroup\$ Commented Jan 3, 2014 at 19:06
  • 1
    \$\begingroup\$ If I am being picky, I would say using namespace std; should be added to the character count. \$\endgroup\$ Commented Jan 4, 2014 at 12:45
1
\$\begingroup\$

Python 2.7 - 115 chars:

oneliner:

>>> a 'I am a text.\nTranspose me.\nCan you do it?' >>> "".join(["".join(i)+'\n' for i in zip(*[x+" "*(len(max(a.splitlines(), key=len))-len(x)) for x in a.splitlines()])]) 'ITC\n ra\naan\nmn \n sy\napo\n ou\nts \need\nx o\ntm \n.ei\n .t\n ?\n' 

and in a cleaner printing:

>>> print "".join(["".join(i)+'\n' for i in zip(*[x+" "*(len(max(a.splitlines(), key=len))-len(x)) for x in a.splitlines()])]) ITC ra aan mn sy apo ou ts eed x o tm .ei .t ? 

in 115 chars:

>>> len(""""".join(["".join(i)+'\n' for i in zip(*[x+" "*(len(max(a.splitlines(), key=len))-len(x)) for x in a.splitlines()])])""") 115 
\$\endgroup\$
5
  • \$\begingroup\$ You are not stripping the trailing whitespace on your lines like the rules require. \$\endgroup\$ Commented Jan 4, 2014 at 12:35
  • \$\begingroup\$ Also, it's actually 116 bytes, \n is considered by len to be a single char, but it's two :) \$\endgroup\$ Commented Jan 4, 2014 at 13:22
  • 1
    \$\begingroup\$ @JoachimIsaksson on unix \n is one. So I say one is fine. \$\endgroup\$ Commented Jan 4, 2014 at 15:44
  • \$\begingroup\$ @Tim len("\n") will show 1, although it's certainly 2 separate characters in the source code. Saving the source to a file will make ls display 116. Just saying that len isn't the best way to measure code size due to escape characters being processed before measuring :) \$\endgroup\$ Commented Jan 4, 2014 at 15:51
  • \$\begingroup\$ @JoachimIsaksson oh, sorry I misunderstood your point. \$\endgroup\$ Commented Jan 4, 2014 at 21:58
1
\$\begingroup\$

Scheme/Racket 113

The text:

(define t (list (string->list "I am a text.") (string->list "Transpose me.") (string->list "Can you do it?") )) 

Without new lines and extra white spaces:

(define s(λ(v x)(if(= x 0)'()(cons(list->string(car v))(s(cdr v)(- x 1))))))(s(apply map list t)(length(car t))) 

The user-friendly version

(define text (list (string->list "I am a text.") (string->list "Transpose me.") (string->list "Can you do it?") )) (define transpose (λ(text length) (if (= length 0) '() (cons (list->string (car text)) (transpose (cdr text) (- length 1))) ))) (transpose (apply map list text) (length (car text))) 
\$\endgroup\$
1
\$\begingroup\$

Python 89 103 chars

def f(a):return'\n'.join([''.join(i).rstrip()for i in zip(*[j+' '*99 for j in a.split('\n')])]).rstrip() 

I feel dirty. 90 104 chars for industrial strength version. :^)

\$\endgroup\$
2
  • \$\begingroup\$ not a function. \$\endgroup\$ Commented Jan 4, 2014 at 13:24
  • \$\begingroup\$ @Tim My bad, fixed. Anyway my solution is inferior to Joachim Isaksson's. I wonder if there's any short way to solve this problem with recursion. \$\endgroup\$ Commented Jan 4, 2014 at 21:08
1
\$\begingroup\$

Mathematica, 95 chars

f=""<>Riffle[Thread@PadRight@Characters@StringSplit[#,"\n"]//.{0->" ",{x___," "..}:>{x}},"\n"]& 
\$\endgroup\$

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.