Transpose a page of text

28

3

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.

Tim Seguine

Posted 12 years ago

Reputation: 824

Later duplicate: http://codegolf.stackexchange.com/q/85255

– msh210 – 9 years ago

I decided to remove the prohibition on language built-ins. – Tim Seguine – 12 years ago

I edited to clarify the trailing whitespace condition. – Tim Seguine – 12 years ago

Are you asking for a function? Is it acceptable to accept a string from STDIN and print the correct output to STDOUT? – Justin – 12 years ago

@Quincunx Yes, I am accepting that as a "function".I will alter the rules to be explicit on that point. – Tim Seguine – 12 years ago

Are blank lines allowed in the input, eg "abc\n\ndef" ? – Lyndon White – 7 years ago

@LyndonWhite I don't remember anymore what I originally intended, but reading what I wrote, I would say yes. – Tim Seguine – 7 years ago

Are trailing new lines allowed? – Asone Tuhid – 7 years ago

@AsoneTuhid I think at this point it is best to say, that is unspecified. If you are following the "no trailing whitespace" rule I don't think it should make a difference. But if it does, then choose whichever you prefer. – Tim Seguine – 7 years ago

The text transpose function cannot be an involution unless you allow for trailing ws. Example: "ac\ndef\n" ->TT-> "a\ncd\nef\n" ~ "a\ncd\nef\n" ->TT-> "acd\nef\n", where *=ws – Emanuel Landeholm – 12 years ago

@EmanuelLandeholm it wasn't intended to be perfect. It was intended to be an involution up to trailing whitespace. "You might have to insert spaces (as in the example) where there were none in order to keep the columns in line." This never requires a whitespace character to be inserted at the end of a line. The correct transformation for your example according to the rules is: "ac\ndef\n"->"ad\ne\ncf\n"->"a*c\ndef\n" Note there is no trailing whitespace at any step and on this input it is an involution. – Tim Seguine – 12 years ago

Answers

2

Japt, 6 bytes

y mx1R

Try it
Run it twice - returns original string


Explanation

y

Transpose the input

m  R

Map over each line

x1

Trim right

Shaggy

Posted 12 years ago

Reputation: 24 623

4

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
  ?

marinus

Posted 12 years ago

Reputation: 30 224

I hope you noticed I removed the prohibition for built-ins. – Tim Seguine – 12 years ago

@Tim: Yes, otherwise I wouldn't have posted this. – marinus – 12 years ago

Is the trailing whitespace rule written unclearly? You seem to have more characters than I expected. – Tim Seguine – 12 years ago

How many characters should I have? The last characters on the string are ?\n. – marinus – 12 years ago

53 I think. I intended that the lines shouldn't have trailing whitespace. So apparently it is unclearly worded. Maybe also not a reasonable requirement, since there are spaces in that position in the input. – Tim Seguine – 12 years ago

You've got trailing whitespace on the mn, ts and tm lines. – J B – 12 years ago

I changed the wording now in the question. I can't/won't penalize you if you don't fix it though. – Tim Seguine – 12 years ago

@Tim: it's fixed now. – marinus – 12 years ago

I'm going to hold off a couple days before marking this as accepted in case someone post something surprising. But I think you got this one. Nothing shorter in APL? – Tim Seguine – 12 years ago

1@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. – marinus – 12 years ago

4

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)

Joachim Isaksson

Posted 12 years ago

Reputation: 1 161

Not exactly compliant. It should be a function take takes a string and returns a string. – Tim Seguine – 12 years ago

@Tim Yes, missed that. Fixed now, thanks. – Joachim Isaksson – 12 years ago

+1 you appear to be the shortest compliant python entry at the moment. – Tim Seguine – 12 years ago

Nice use of map. I keep looking for a place to use that... and you just beat me to it. ;) – boothby – 12 years ago

4

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).

Wayne Conrad

Posted 12 years ago

Reputation: 163

Nice. You can strip out one more character by replacing "\n" with ?\n. – O-I – 12 years ago

Also, the .to_a is superfluous. You can gain another 5 characters there. – O-I – 12 years ago

@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. – Wayne Conrad – 12 years ago

I see. Good to know. Consider us even for showing me a few String methods in Ruby I should be using more often. Cheers! – O-I – 12 years ago

2Some of the code golf challenges have renewed my interest in learning ruby. – Tim Seguine – 12 years ago

4

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.

Sven Hohenstein

Posted 12 years ago

Reputation: 2 464

4

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
$ 

Digital Trauma

Posted 12 years ago

Reputation: 64 644

You appear to be breaking the rule "Your result must not have trailing whitespace on any line." – Tim Seguine – 12 years ago

@TimSeguine Oops I missed that one. I just fixed it in the latest edit. – Digital Trauma – 12 years ago

3

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");}}

wjl

Posted 12 years ago

Reputation: 171

I think you can take advantage of implicit int to shorten some of your declarations, or is that illegal now? – Tim Seguine – 12 years ago

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. – wjl – 12 years ago

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? – Tim Seguine – 12 years ago

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. – wjl – 12 years ago

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. – Konrad Borowski – 12 years ago

To answer which whitespace must be stripped. After transposition there is most likely going to be trailing " " characters on some lines. These should be deleted. – Tim Seguine – 12 years ago

unlucky line break. The character in the quotation marks is a space. – Tim Seguine – 12 years ago

3

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)

Avi

Posted 12 years ago

Reputation: 261

I can't test this one, but it looks compliant – Tim Seguine – 12 years ago

3

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

memnon

Posted 12 years ago

Reputation: 161

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. – Tim Seguine – 12 years ago

3

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*$/}

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

manatwork

Posted 12 years ago

Reputation: 17 865

+1 You golfed it better in any case. – Tim Seguine – 12 years ago

2

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.

mbomb007

Posted 12 years ago

Reputation: 21 944

2

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>

edc65

Posted 12 years ago

Reputation: 31 086

2

Perl 5, 25 bytes

Note that this uses ANSI escape sequences and as such does not work on TIO, you can however see it in action here.

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

Explanation

This code first changes the list separator ($") value to be a vertical tab, followed by the ANSI escape sequence for 'go backwards 1 column' (\x1b[1D), 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) 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.

Try it online!

Dom Hastings

Posted 12 years ago

Reputation: 16 415

1Oh my god, the sheer horror! I love it! – Tim Seguine – 7 years ago

2

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.

O-I

Posted 12 years ago

Reputation: 759

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. :( – Wayne Conrad – 12 years ago

2I 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! – O-I – 12 years ago

2

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!

elixenide

Posted 12 years ago

Reputation: 250

@TimSeguine Warnings output on screen though right? You'll have to use @ to suppress warnings. – ericw31415 – 9 years ago

@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. – Tim Seguine – 9 years ago

It's allowed? If that is true, then I didn't know that. – ericw31415 – 9 years ago

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. – Tim Seguine – 12 years ago

2

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)&

Murta

Posted 12 years ago

Reputation: 339

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. – Tim Seguine – 12 years ago

hi @Tim, now it is a function f!.. tks – Murta – 12 years ago

2

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

chinese perl goth

Posted 12 years ago

Reputation: 1 089

2

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.";

Martin Ender

Posted 12 years ago

Reputation: 184 808

Eligible or not, it is a great late answer. Seems like the hardest part for this answer was dealing with the trailing spaces. – Tim Seguine – 11 years ago

@TimSeguine Indeed. Without a built-in trimming operator, doing this manually in CJam is surprisingly cumbersome (user23013's suggestion already improved it considerably). – Martin Ender – 11 years ago

1

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!

gastropner

Posted 12 years ago

Reputation: 3 264

1

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!

KSmarts

Posted 12 years ago

Reputation: 1 830

1

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?

Bolce Bussiere

Posted 12 years ago

Reputation: 970

I would use cutLF. – FrownyFrog – 8 years ago

1Save 1 character with 0|:>@cutLF – FrownyFrog – 8 years ago

1

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 :)

Visckmart

Posted 12 years ago

Reputation: 151

1There'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) – Jo King – 7 years ago

Unfortunately Your result must not have trailing whitespace on any line. – Jo King – 7 years ago

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. – Visckmart – 7 years ago

The part that seems to catch people out is *on any line*. e.g. This has extra whitespace on the second line

– Jo King – 7 years ago

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 :) – Visckmart – 7 years ago

1

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!

Chas Brown

Posted 12 years ago

Reputation: 8 959

Unfortunately Your result must not have trailing whitespace on any line. Also it seems to print a lot of extra newlines. – Jo King – 7 years ago

@Jo King: Thx - My new toy did not work here! – Chas Brown – 7 years ago

This still has trailing whitespace on some lines for example

– Jo King – 7 years ago

@Jo King: Ah yes. Fixed now. – Chas Brown – 7 years ago

1

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.

Jacob Watson

Posted 12 years ago

Reputation: 131

"Your result must not have trailing whitespace on any line." – Tim Seguine – 7 years ago

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). – sundar - Reinstate Monica – 7 years ago

@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. – Jacob Watson – 7 years ago

1

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)

Kevin Cruijssen

Posted 12 years ago

Reputation: 67 575

1

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

sundar - Reinstate Monica

Posted 12 years ago

Reputation: 5 296

1

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)

sundar - Reinstate Monica

Posted 12 years ago

Reputation: 5 296

You can remove the .. Best practices go out of the window in code golf :-P – Luis Mendo – 7 years ago

@LuisMendo Ha, I didn't even realize I'd added the ., automatic muscle memory. – sundar - Reinstate Monica – 7 years ago

1

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?`));

MattH

Posted 12 years ago

Reputation: 171

Seems like there is still potential to golf this; a lot of big names and movable snippets – MattH – 7 years ago

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) – Tim Seguine – 7 years ago

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") – Tim Seguine – 7 years ago

Nevermind, I realized that will delete empty lines – Tim Seguine – 7 years ago

You've made me realize my solution incorrectly handles empty lines. Regardless, thanks for your solution. – MattH – 7 years ago

1

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;
}

David

Posted 12 years ago

Reputation: 111

I assume you use using namespace std;. – Konrad Borowski – 12 years ago

@xfix Not normally, but I did for this – David – 12 years ago

1If I am being picky, I would say using namespace std; should be added to the character count. – Tim Seguine – 12 years ago

1

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

0x90

Posted 12 years ago

Reputation: 111

You are not stripping the trailing whitespace on your lines like the rules require. – Tim Seguine – 12 years ago

Also, it's actually 116 bytes, \n is considered by len to be a single char, but it's two :) – Joachim Isaksson – 12 years ago

1@JoachimIsaksson on unix \n is one. So I say one is fine. – Tim Seguine – 12 years ago

@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 :) – Joachim Isaksson – 12 years ago

@JoachimIsaksson oh, sorry I misunderstood your point. – Tim Seguine – 12 years ago

1

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.

Ilmari Karonen

Posted 12 years ago

Reputation: 19 513

Your assumption is correct. It should work on any ASCII text under the assumptions allowed in the rules. – Tim Seguine – 12 years ago

1

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. :^)

TrevorM

Posted 12 years ago

Reputation: 111

not a function. – Tim Seguine – 12 years ago

@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. – TrevorM – 12 years ago

1

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)))

tasegula

Posted 12 years ago

Reputation: 141

1

Haskell

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

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

randomusername

Posted 12 years ago

Reputation: 127

I'm almost sure you can remove some of the whitespace here. But otherwise, great solution. – Konrad Borowski – 12 years ago

3This 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. – marinus – 12 years ago

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.) – Tim Seguine – 12 years ago

1

Mathematica, 95 chars

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

alephalpha

Posted 12 years ago

Reputation: 23 988

1

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"

tmartin

Posted 12 years ago

Reputation: 3 917

The output appears to be an array of strings? – Tim Seguine – 12 years ago

@Tim It is. If you want a single string then add three chars. {\/:x@'/:!max@#:'x:`:x}` for 26. – tmartin – 12 years ago

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. – Tim Seguine – 12 years ago

@Tim should be fixed now. Kills my bytecount though – tmartin – 12 years ago

I suspected it might :( , but a spec is a spec. – Tim Seguine – 12 years ago

1

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
}

Krzysztof Atłasik

Posted 12 years ago

Reputation: 189

0

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.

Titus

Posted 12 years ago

Reputation: 13 814

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. – Tim Seguine – 8 years ago

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. – Tim Seguine – 8 years ago

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. – Tim Seguine – 8 years ago

@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. – Titus – 8 years ago

@TimSeguine ... and the default options include error_reporting=E_ALL&~E_NOTICE (undefined constant "f", assuming string is a notice, not a warning) – Titus – 8 years ago

If you don't like the rules then don't post an answer, it's that simple. Being able to follow a spec exactly is an important part of being a good engineer. I have relatively little interest in this site anymore, so any time spent on arguing about the spec is time I consider wasted. – Tim Seguine – 8 years ago

@TimSeguine Sorry. let me rephrase: not "ridiculous" but "unusual". But ok. I´d love to see your solutions to the issues. – Titus – 8 years ago

1I 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. – Tim Seguine – 8 years ago

0

Perl 5, 81 bytes

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

Try it online!

Xcali

Posted 12 years ago

Reputation: 7 671

0

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

dragonite44

Posted 12 years ago

Reputation: 91

0

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.

hakr14

Posted 12 years ago

Reputation: 1 295

From the spec: *"Your result must not have trailing whitespace on any line."* - it caught me out as well. – Shaggy – 7 years ago

0

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

Taylor Scott

Posted 12 years ago

Reputation: 6 709

0

Charcoal, 7 3 bytes (non-competing)

↓S‖

-4 bytes thanks to @ASCII-only.

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

Non-competing because it contains trailing spaces.

Explanation:

Print the multi-line input in a downward direction:

Print(:Down, InputString());
↓S

Reflect everything so the lines are outputted in the correct order:

Reflect();
‖

Kevin Cruijssen

Posted 12 years ago

Reputation: 67 575

I think there is a similar challenge that has the rules people seem to expect for trailing whitespace. – Tim Seguine – 7 years ago

@TimSeguine Do you perhaps have a link to that similar challenge? Then I will delete this answer here and post it there. – Kevin Cruijssen – 7 years ago

http://codegolf.stackexchange.com/q/85255 expects the input strings to all be the same size, so they didn't have to invent any special rules for jagged input like I did. – Tim Seguine – 7 years ago

1maybe 3 :P – ASCII-only – 7 years ago

@ASCII-only Thanks! Btw, is there any way in Charcoal to remove those trailing spaces to make it compatible? – Kevin Cruijssen – 7 years ago

@KevinCruijssen There is, kinda but there needs to be absolutely nothing there (i.e. not been written on before). I'm not sure what would be the best way to introduce a delete command. Maybe a new "printable" character (like \x00, \n and \r)?

– ASCII-only – 7 years ago

@ASCII-only I indeed saw the ToggleTrim, but unfortunately it doesn't work with the challenge. Probably because of what you state: there should be nothing written on before. And a replace or delete function would be useful, but I wouldn't add it just for the sake of this challenge. Having to remove trailing whitespaces is kinda an exception for code-golf challenges..

– Kevin Cruijssen – 7 years ago

@KevinCruijssen Yeah, IMO the biggest issue would be supporting a wide range of ways to delete (i.e. same capabilities as the current printing methods) – ASCII-only – 7 years ago

0

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));

Tim Seguine

Posted 12 years ago

Reputation: 824

0

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)

Impredicative

Posted 12 years ago

Reputation: 101

It's usually good to add some explanatory text. It helps those who don't know the language to decide to vote you up. :) – luser droog – 12 years ago

0

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"

streetster

Posted 12 years ago

Reputation: 3 635

0

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.

ericw31415

Posted 12 years ago

Reputation: 2 229