Classifique todas as linhas horizontalmente por referência a colunas em uma linha específica

5

Eu preciso classificar horizontalmente, não verticalmente, e sort parece ser projetado para operação vertical. q Por exemplo, tenho três linhas da seguinte forma:

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

Todas as linhas têm o mesmo número de colunas, separadas por / . Eu quero que as colunas sejam reorganizadas de acordo com a ordem alfabética na linha 1. Assim, ela se tornará:

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

Isso pode ser melhor visualizado conforme mostrado abaixo:

, por exemplo, classificar por coluna em uma planilha.

    
por Simonmdr 12.06.2016 / 02:36

4 respostas

4

Com o GNU awk , você pode ditar a ordem na qual os arrays são percorridos, configurando sorted_in em PROCINFO . Nesse caso, defina-o como @val_str_asc para forçar que as matrizes sejam percorridas em ordem crescente de valores.

Em seguida, divida a primeira linha em uma matriz a Finalmente, para cada linha, percorra a matriz e imprima os campos correspondentes às chaves à medida que são recuperados.

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

Ou com 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
    
por 12.06.2016 / 05:22
2

Eu acho que a abordagem básica seria

Então

perl -F'/' -alne '
   our @inds = sort { $F[$a] cmp $F[$b] } 0..$#F if $. == 1; 
   print join "/", @F[@inds]
' file
    
por 12.06.2016 / 03:42
2

No BSD com o utilitário rs :

$ rs -T -c'/' <data.in | sort | rs -T -C'/' >data.out
  • -T transposes
  • -c'/' define o delimitador da coluna de entrada
  • -C'/' define o delimitador da coluna de saída

Olhando para isso:

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

Removendo o / supérfluo no final:

$ sed 's#/$##' data.out
apple/banana/mango/orange
onion/potato/garlic/tomato
carpet/chair/window/table
    
por 29.07.2016 / 22:56
2
  1. Usando GNU datamash , transpõe , classifica e transpõe novamente:

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

    Saída:

    apple/banana/mango/orange
    onion/potato/garlic/tomato
    carpet/chair/window/table
    
  2. Várias ferramentas de software :

    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
    

    Como isso funciona: join pode reordenar colunas, por meio de parâmetros passados para sua opção -o . Então (usando sem variáveis e sem arrays) o truque é gerar esses parâmetros:

    1. head obtém a primeira linha,
    2. tr converte isso para várias linhas,
    3. quais nl números,
    4. sort pela segunda coluna, (ou seja, maçã , etc.),
    5. e cut da lista reordenada de números na coluna 1,
    6. sed converte os números para um formato que join gosta.
por 16.06.2016 / 17:00