# Transpose columns in table

Let's say you've got a table of data:

meter_id date   0000 0600 1200 1800
0        030915 10   20   30   40
1        030915 15   7    49   2


where the last four columns are meter readings at different times. You want to output

meter_id date   time reading
0        030915 0000 10
0        030915 0600 20


etc.

Your input and output will not have headers, unlike in this example. The set of columns you'll transpose will be provided as numeric arguments to your program, from 1 onwards. Input is stdin and output is stdout.

So here's an example of it actually being used.

$./tpose 3 4 5 6  Stdin: 0 030915 10 20 30 40 1 030915 15 7 49 2  Stdout: 0 030915 3 10 0 030915 4 20 0 030915 5 30 0 030915 6 40 1 030915 3 15 1 030915 4 7 1 030915 5 49 1 030915 6 2  The third column contains values from 3 to 6. This is because the reading is from columns 3 to 6 from the input table. Happy golfing. • Can you post some example inputs and outputs? – kirbyfan64sos Oct 9 '15 at 14:18 • Is 0600 30 in the example just wrong (1200 is 30), or are you trying to do cumulative readings (so adding the current 20 to the previous 10)? – Geobits Oct 9 '15 at 14:20 • @Geobits Fixed. – jkabrg Oct 9 '15 at 14:21 • You say in the text that the values in the third column of the output are 3 to 6, but they are actually 2 to 5. Which one is right? Right now, it looks like you're using 1-based column indices in the input, and 0-based in the output. – Reto Koradi Oct 9 '15 at 15:16 • Do the columns to be transposed always form a contiguous range? Can other columns appear after them? If yes, where should the transposed columns appear in the output? Are the columns to be transposed always given in ascending order, and can they contain the same column twice? And if so, can we reorder them in the output, or collapse duplicates? – Ilmari Karonen Oct 10 '15 at 17:00 ## 6 Answers # kdb k, 101 bytes 1@"\n"/:{"\n"/:{" "/:(r@&{~#&x=a}'!#r),(,$1+a@x),,c@x}'!#c::(r::" "\:x)@a::-1+.:'.z.x}'-1_"\n"\:0::0;


Me: (reads the word "transpose" in the title) K will be perfect for this! It'll kick everything else's hind!

20 minutes and 101 bytes later

Me: Idiot.

# Ruby, 88 84 bytes

Input is tab-separated. Annoyingly, Ruby gets pulls from files whose names match those from ARGV, but those don't exist so the program errors out. To work around this, I have to use STDIN.gets to get the actual correct input.

-4 bytes by remembering that I don't actually need to use scan since I'm only matching the pattern once per line anyways, so =~ for a single regex match saves bytes.

($_=~/(\d+ \w+ )(.*)/;i=-1;puts$2.split.map{|s|"#$1#{$*[i+=1]}	"+s})while STDIN.gets


Try it online!

perl -E'while(<STDIN>){@f=(0,split);@i=0..$#f,@i[@ARGV]=0;say"@f[grep$_,@i] $_$f[$_]"for@ARGV}'  # Haskell (195 bytes) import System.Environment main=do s<-getArgs>>=return.map(\a->read a-1);interact$unlines.map unwords.t s.map words.lines
t g r=[[a!!j|j<-[0..length a-1],not$jelemg]++show(j+1):[a!!j]|a<-r,j<-g]  Ungolfed Haskell (398 bytes): import System.Environment import Prelude main = do js <- getArgs >>= return . map (\a -> read a - 1) interact$ unbr . (tpose js) . br

br = map words . lines

xs excludingFrom es = [xs !! j | j <- [0..length xs - 1], not $j elem es] tpose rows js = [row excludingFrom js ++ [show (j+1)] ++ [row !! j] | row <- rows, j <- js] unbr = unlines . map (foldr1$ \t a -> t++"\t"++a)

• p>>=return.f should generally be written f<$>p. In this case, though, you can golf more by just using s<-getArgs and applying the parsing inline. Since you use map three times, you should write m=map on its own line and use that. – dfeuer Jul 3 '19 at 4:02 # PHP, 90 bytes while($r=fgetcsv(STDIN,0,' '))foreach($argv as$a)if($a|0)echo"$r[0] $r[1]$a {$r[$a-1]}
";


Input and output with single space delimiter.

Try it online!

# PHP, 109 bytes

while($r=preg_split("/\s+/",fgets(STDIN),0,1))foreach($argv as$a)if($a|0)echo"$r[0]\t$r[1]\t$a\t{$r[\$a-1]}
";


Or with I/O exactly as shown above, using fixed width columns.

Try it online!

# APL (Dyalog Unicode), 56 bytesSBCS

Anonymous prefix lambda. Takes column numbers for "transposition" as right argument and prompts via stdin for filename of table.

{(t[;⍵~⍨⍳≢⍉t]⌿⍨≢⍵),(⍪,⍨⍵⍴⍨≢),t[;⍵]⊣t←↑(∊∘⎕D⊆⊢)¨⊃⎕NGET⍞1}


Try it online!

{} "dfn"; right argument (column numbers) is ⍵:

⍞1 prompt for file name from stdin and juxtapose with 1 (indicating that we want a list of strings)
["tpose",1]

⎕NGETget the native file's (content,encoding,newline)
[["0 030915 10 20 30 40","1 030915 15 7 49 2"],"UTF-8-NOBOM",[10]]

⊃ pick the first of those (content)
["0 030915 10 20 30 40","1 030915 15 7 49 2"]

()¨ apply the following tacit function to each line:

∊ the characters that are members
∘ of
⎕D the set of digits
[[1,0,1,1,1,1,1,1,0,1,1,0,1,1,0,1,1,0,1,1],[1,0,1,1,1,1,1,1,0,1,1,0,1,0,1,1,0,1]]

⊆ indicate the sub-partitions of

⊢ the line
[["0","030915","10","20","30","40"],["1","030915","15","7","49","2"]]

↑ up the rank by mixing the list (rank 1) of lists into a matrix (rank 2)
[["0","030915","10","20","30","40"],
 ["1","030915","15","7" ,"49","2" ]]

t← assign that to t (for table)

⊣ discard that in favour of

t[;⍵] all rows of the subset of columns of t enumerated in the argument
[["10","20","30","40"],
 ["15","7" ,"49","2" ]]

, ravel (flatten that)
["10","20","30","40","15","7","49","2"]

() apply the following tacit function to that:

≢ the tally of elements
8

⍵⍴⍨ use that to reshape the number of columns to be "transposed"
[3,4,5,6,3,4,5,6]

,⍨ to that, append

⍪ the table-fied (made into single-column table) argument (the "transposed" columns)
[[3,"10"],
 [4,"20"],
 [5,"30"],
 [6,"40"],
 [3,"15"],
 [4,"7" ],
 [5,"49"],
 [6,"2" ]]

(), prepend the following:

≢⍵ the tally of columns to be "transposed"
4

…⌿⍨ use that to vertically replicate the rows of…

t[;] all rows of the following columns of the table:

⍉t transpose the table
[["0" ,"1" ],
 ["030915","030915"],
 ["10" ,"15" ],
 ["20" ,"7" ],
 ["30" ,"49" ],
 ["40" ,"2" ]]

≢ the tally of rows
6

⍳ɩndices until that
[1,2,3,4,5,6]

⍵~⍨ except the "transposed" column numbers
[1,2]

[["0","030915"],
 ["1","030915"]]

[["0","030915"],
 ["0","030915"],
 ["0","030915"],
 ["0","030915"],
 ["1","030915"],
 ["1","030915"],
 ["1","030915"],
 ["1","030915"]]

[["0","030915",3,"10"],
 ["0","030915",4,"20"],
 ["0","030915",5,"30"],
 ["0","030915",6,"40"],
 ["1","030915",3,"15"],
 ["1","030915",4,"7" ],
 ["1","030915",5,"49"],
 ["1","030915",6,"2" ]]