5

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.

1
  • 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, 2016 at 20:48

4 Answers 4

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
3
  • 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, 2016 at 12:37
  • @Simonmdr, what version of gawk do you have? Please provide output from gawk --version
    – iruvar
    Jun 13, 2016 at 13:13
  • GNU Awk 4.1.3, API: 1.1 (GNU MPFR 3.1.3, GNU MP 6.1.0)
    – Simonmdr
    Jun 13, 2016 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
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
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.
2
  • 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. Jul 29, 2016 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, 2016 at 20:57

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .