4

I need to sort horizontally, not vertically, and sort seems to be designed for vertical operation. q E.g., I have three rows as follows:

banana/orange/apple/mango
potato/tomato/onion/garlic
chair/table/carpet/window

All rows have the same number of columns, separated by a /. I want the columns to be re-arranged according to alphabetical order in row 1. So it will become:

apple/banana/mango/orange
onion/potato/garlic/tomato
carpet/chair/window/table

This might be better visualized as shown below:

text in colored columns

i.e., like sort-by-column in a spreadsheet.

  • You don't happen to be on a BSD system (OS X, for example)? If so, do you have the the rs utility? – Kusalananda Jul 29 '16 at 20:48
4

With GNU awk, you may dictate the order in which arrays are traversed by setting sorted_in within PROCINFO. In this instance, set it to @val_str_asc to force arrays to be traversed in ascending order of values.

Next split the first line into an array a Finally, for each line, traverse the array and print fields corresponding to the keys as they are retrieved.

awk -F'/' 'BEGIN{PROCINFO["sorted_in"]="@val_str_asc"};
   FNR == 1{n = split($0, a)};
   {x=0; for (k in a) printf "%s%s", $k, ++x == n? "\n": FS}' file

apple/banana/mango/orange
onion/potato/garlic/tomato
carpet/chair/window/table

Or, with python

from __future__ import print_function
with open('file') as f:
    keys = next(f).rstrip('\n').split('/')
    print(*sorted(keys), sep='/')
    for line in f:
            g = (m for l, m in sorted(zip(keys, line.rstrip('\n').split('/'))))
            print(*g, sep='/')

apple/banana/mango/orange
onion/potato/garlic/tomato
carpet/chair/window/table
|improve this answer|||||
  • So I tried: gawk -F'/' 'BEGIN{PROCINFO["sorted_in"]="@val_str_asc"}; FNR == 1{n = split($0, a)}; {x=0; for (k in a) printf "%s%s", $k, ++x == n? "\n": FS}' file ...and I got error msg "'FNR' is not recognised as an internal or external command"', then I tried removing the two line breaks in the command and got an output file that just had "sssssssssssss" in it, and then tried removing both the two line breaks and the two semi-colons (just for the hell of it because I'm flying blind) and got the same output: "sssssssssssssss". – Simonmdr Jun 12 '16 at 12:37
  • @Simonmdr, what version of gawk do you have? Please provide output from gawk --version – iruvar Jun 13 '16 at 13:13
  • GNU Awk 4.1.3, API: 1.1 (GNU MPFR 3.1.3, GNU MP 6.1.0) – Simonmdr Jun 13 '16 at 17:45
2

I think the basic approach would be

So

perl -F'/' -alne '
   our @inds = sort { $F[$a] cmp $F[$b] } 0..$#F if $. == 1; 
   print join "/", @F[@inds]
' file
|improve this answer|||||
2

On BSD with the rs utility:

$ rs -T -c'/' <data.in | sort | rs -T -C'/' >data.out
  • -T transposes
  • -c'/' sets the input column delimiter
  • -C'/' sets the output column delimiter

Looking at it:

$ cat data.in
banana/orange/apple/mango
potato/tomato/onion/garlic
chair/table/carpet/window

$ cat data.out
apple/banana/mango/orange/
onion/potato/garlic/tomato/
carpet/chair/window/table/

Removing the superfluous / at the end:

$ sed 's#/$##' data.out
apple/banana/mango/orange
onion/potato/garlic/tomato
carpet/chair/window/table
|improve this answer|||||
2
  1. Using GNU datamash, transpose, sort, and transpose again:

    datamash -t '/' transpose < file | datamash -t '/' -s -g1 transpose
    

    Output:

    apple/banana/mango/orange
    onion/potato/garlic/tomato
    carpet/chair/window/table
    
  2. Various software tools:

    join -a 1 -t / -o $( head -n 1 file | \
                         tr / '\n' | \ 
                         nl  -n ln | \
                         sort  -k2 | \
                         cut   -f1 | \
                         sed -n 's/^/1./;H;1h;${x;s/\n/,/g;s/ //gp}' ) \
          file /dev/null
    

    How that works: join can reorder columns, via parameters passed to its -o option. So (using no variables and no arrays) the trick is to generate those parameters:

    1. head gets the first line,
    2. tr converts that to several lines,
    3. which nl numbers,
    4. sort by the 2nd column, (i.e. apple, etc.),
    5. and cut the reordered list of numbers in column #1,
    6. sed converts the numbers to a format that join likes.
|improve this answer|||||
  • 1
    This answer is wrong, because you misread/misunderstood the question. (Note that the question shows the desired output, and your output does not match it.) Your comment on the question seems to reflect the same misunderstanding. – G-Man Says 'Reinstate Monica' Jul 29 '16 at 18:55
  • @G-Man, you're right -- thanks for the correction and the OP color coding. (I now recall having having mistook the OP's needed output for a typo.) In light of which, I've made a revised and somewhat different answer. – agc Jul 29 '16 at 20:57

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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