¿Cómo reordenar una gran cantidad de columnas?

¿Cómo reordenar una gran cantidad de columnas?

Estoy buscando una línea canalizable para reordenar una gran cantidad de columnas (donde ingresar manualmente los números de columna, por ejemplo, con un awkcomando como este, awk '{print $3,$2,$1}'no es factible). El orden podría darse mediante un esquema de clasificación (alfabético, numérico, algo así como "ordenar", pero actuando en columnas en lugar de filas) o darse arbitrariamente en un archivo de texto.

Respuesta1

Solución sencilla con Perl.

Primero complete su conjunto de valores.

➜ ~ x="$(cat << END
22      79      83      16      25      1       4       82      34      68
48      43      2       26      39      2       71      43      57      41
77      70      73      18      76      33      21      54      67      50
6       65      46      92      25      70      53      28      3       40
32      60      76      39      26      44      34      91      24      39
59      75      96      85      52      98      69      28      72      94
48      0       88      55      6       78      1       54      83      81
3       43      48      24      23      87      28      98      38      67
97      73      74      24      92      67      1       27      90      85
32      55      52      44      26      37      87      37      100     92
END
)"
➜  ~ perl -lane '@i=sort({ @F[$a] <=> @F[$b] } 0..$#F) if $.==1; 
                 print join("\t", @F[@i])' <<< "$x"      

1       4       16      22      25      34      68      79      82      83
2       71      26      48      39      57      41      43      43      2
33      21      18      77      76      67      50      70      54      73
70      53      92      6       25      3       40      65      28      46
44      34      39      32      26      24      39      60      91      76
98      69      85      59      52      72      94      75      28      96
78      1       55      48      6       83      81      0       54      88
87      28      24      3       23      38      67      43      98      48
67      1       24      97      92      90      85      73      27      74
37      87      44      32      26      100     92      55      37      52

  • -a: habilita la división automática que completa automáticamente la @Fmatriz
  • -n: lee cada línea en un bucle while
  • $#F: devuelve el índice basado en 0 más grande de la matriz
  • <=>: operador de comparación para funciones de clasificación (solo entrada numérica, para comparaciones de cadenas se utiliza cmp)
  • sort: devuelve los índices ordenados de la matriz 0..$#F(usando las variables integradas $ay $b)
  • @i: contiene la matriz de índices ordenados para @F(en este ejemplo, @i = 5 6 3 0 4 8 9 1 7 2)
  • $. == 1: y hazlo solo en la primera línea
  • @F[@i]: ordena cada línea según los índices ordenados

Fuente:https://learnbyexample.gitbooks.io/command-line-text-processing/content/perl_the_swiss_knife.html

Respuesta2

Aquí hay una solución transmitible.

Supongo que desea ordenar según la primera fila de las columnas; de lo contrario, adáptese para obtener la clave de clasificación de otro lugar.

Generar clave de clasificación (reutilizando la matriz de Rush):

echo -e  "b a c\n5 4 6\n8 7 9" > data

key=$(head -n1 data | sed 's/ \+/\n/g' | nl -n ln | sort -k2 | cut -f1)
    

$keyahora tiene:

2
1
3

Ahora use la clave para ordenar columnas:

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

{ 
  for(i=1; i<=length(order); i++) { 
    printf("%s ", $order[i])
  }
  printf("\n");
}' data

Producción:

a b c 
4 5 6 
7 8 9

Respuesta3

No estoy seguro de que sea la mejor solución y no estoy seguro de que funcione rápidamente en tablas enormes, pero debería 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}}'

Cómo funciona: transpone la tabla, luego la clasifica y la vuelve a transponer.

por cierto echo -e "2 1 3\n5 4 6\n8 7 9"resultará en

2 1 3
5 4 6
8 7 9

Después del trabajo del guión resultará

1 2 3
4 5 6
7 8 9

PD. Creo que es posible ordenar una matriz en awk, lamentablemente no tengo tiempo suficiente para hacerlo.

Respuesta4

Suponiendo que su archivo es xy.dat y separado por espacios en blanco:

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

Como mis datos de prueba eran numéricos ascendentes, uso sort -nr en el corazón para hacerlos descendentes y ver algún efecto.

Ahora, para hacerlo configurable, uno simplemente pasaría como parámetros los indicadores de clasificación, que permiten ascendente (ninguno) y descendente -r (inverso), pero también -n (numérico) y muchos más (ver: sort --help). Otra cosa que te puede gustar configurar es el delimitador. ¿En blanco/tabulador/punto y coma/coma? ¿Quizás a un grupo de expresiones regulares le gusta "[ \t]"significar espacio en blanco o tabulación? Pero, ¿qué utilizar entonces para la salida? Y no le gustaría codificar el nombre del archivo, sino utilizar su programa como filtro. Aquí hay un enfoque rápido:

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

invocación:

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 

Vea cómo se ordena de forma predeterminada con -- (alfabético: 10 11 9), inverso (9 10 11) o numérico (11 10 9).

Sería útil principalmente cómo enmascarar espacios en blanco, tabulaciones, etc., si se documentan.

información relacionada