Como reordenar um grande número de colunas?

3

Estou à procura de um one-liner para reordenar um grande número de colunas (onde inserir manualmente os números das colunas, por exemplo, um comando awk , como awk '{print $3,$2,$1}' , não é viável). A ordem poderia ser dada por um esquema de ordenação (alfabético, numérico - assim como 'sort', mas agindo em colunas em vez de linhas.) Ou ser arbitrariamente dado em um arquivo de texto.

    
por gaffa 17.04.2012 / 10:36

3 respostas

1

Aqui está uma solução de streamable.

Suponho que você queira classificar com base na primeira linha das colunas, caso contrário, adapte-se para obter a chave de classificação de outro lugar.

Gerar chave de classificação (reutilizando a matriz do Rush):

echo -e  "2 1 3\n5 4 6\n8 7 9" > data

key=$(head -n1 data | tr -s ' ' | tr ' ' '\n' | cat -n \
      | sort -k2 | sed 's/^ *\(.*\)\t.*//')

$key agora é válido:

2
1
3

Agora use a chave para classificar as colunas:

cat data | awk -v key="$key" '
BEGIN { split(key, order, "\n") }

{ 
  for(i in order) { 
    printf("%s ", $order[i])
  }
  printf("\n");
}'

Saída:

1 2 3 
4 5 6 
7 8 9
    
por 17.04.2012 / 12:24
0

Não sei se é a melhor solução e não tenho certeza de que funcionará rapidamente em tabelas grandes, mas deve funcionar:

echo -e  "2 1 3\n5 4 6\n8 7 9"  | \
awk '{for (i=1;i<=NF;i++) {a[NR,i]=$i} } \
     NF>p {p=NF} \
     END {for (j=1;j<=p;j++) {str=a[1,j]; \
     for (i=2;i<=NR;i++) {str=str" "a[i,j];}print str}}' \ 
     | sort -n  | \
awk '{for (i=1;i<=NF;i++) {a[NR,i]=$i} } \
     NF>p {p=NF} \
     END {for (j=1;j<=p;j++) {str=a[1,j]; \
     for (i=2;i<=NR;i++) {str=str" "a[i,j];}print str}}'

Como funciona: transpõe a tabela, depois ordena a tabela e a transpõe de volta.

btw echo -e "2 1 3\n5 4 6\n8 7 9" resultará em

2 1 3
5 4 6
8 7 9

Após o trabalho de script, isso resultará em

1 2 3
4 5 6
7 8 9

ps. Eu acho que é possível classificar o array no awk, infelizmente não tenho tempo suficiente para fazê-lo.

    
por 17.04.2012 / 11:40
0

Assumindo que seu arquivo é xy.dat e separado por espaço em branco:

cat xy.dat | while read line ; do  
   echo $line | tr ' ' '\n' | sort -nr | tr '\n' ' '
   echo
done

Como meus dados de teste eram ascendentes numéricos, eu uso sort -nr no coração para diminuí-lo e ver algum efeito.

Agora, para torná-lo configurável, basta passar como parâmetros os sinalizadores para classificação, o que permite ascendente (nenhum) e descendente -r (reverso), mas também -n (numérico) e muito mais (veja: sort --help ). Outra coisa que você pode gostar de configurar é o delimitador. Blank / Tab / ponto-e-vírgula / vírgula? Talvez um grupo regex como "[ \t]" signifique em branco ou tabulação? Mas o que usar para saída então? E você não gostaria de codificar o nome do arquivo, mas usar seu programa como um filtro. Aqui está uma abordagem rápida:

#!/bin/bash
flags=$1
delim=$2 
while read line ; do  
    echo $line | tr "$delim" '\n' | sort $flags | tr '\n' "$delim"
    echo
done

invocação:

cat num.dat | bash colsort.sh "-nr" ' ' 
4 3 2 1 
8 7 6 5 
11 10 9 

cat num.dat | bash colsort.sh "-r" ' ' 
4 3 2 1 
8 7 6 5 
9 11 10 

cat num.dat | bash colsort.sh "--" ' ' 
1 2 3 4 
5 6 7 8 
10 11 9 

Veja como ele é classificado por padrão com - (alfabético: 10 11 9), reverso (9 10 11) ou numérico (11 10 9).

Principalmente como mascarar em branco, separador e assim por diante, seria útil, se documentado.

    
por 17.04.2012 / 23:02

Tags