多数の列を並べ替える方法は?

多数の列を並べ替える方法は?

私は多数の列を並べ替えるためのパイプライン可能な限り行のコードを探しています(たとえば、awkこのようなコマンドで列番号を手動で入力することはawk '{print $3,$2,$1}'不可能です)。順序は、ソート方式(文字、数字 - 「ソート」と似ていますが、行ではなく列に対応します)を使用するか、テキストファイルで任意に指定できます。

答え1

Perlを使ったシンプルなソリューション。

値の配列を埋めることから始めます。

➜ ~ 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@F: 配列の自動分割と自動塗りつぶしの有効化
  • -n:while ループの各行を読み込みます。
  • $#F: 配列内の最大のゼロベースのインデックスを返します。
  • <=>:ソート機能の比較演算子(数値入力のみ可能、文字列比較に使用cmp
  • sort:配列内のソートされたインデックスを返します0..$#F(組み込み$a合計$b変数を使用)。
  • @i@F:(この場合)を含むソートされた@i = 5 6 3 0 4 8 9 1 7 2インデックス配列
  • $. == 1:最初の行でのみ実行されます。
  • @F[@i]:ソートされたインデックスに従って各行をソートします。

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

答え2

これはストリーミング可能なソリューションです。

列の最初の行に基づいてソートし、そうでなければ他の場所でソートキーを取得するように調整するとします。

ソートキーの生成(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)
    

$key現在確立されている:

2
1
3

次に、キーを使用して列をソートします。

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

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

出力:

a b c 
4 5 6 
7 8 9

答え3

これが最善の解決策であるか、巨大なテーブルで素早く実行されるかはわかりませんが、うまくいきます。

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}}'

仕組み:テーブルを転置してから、テーブルを並べ替えて再配置します。

ところでecho -e "2 1 3\n5 4 6\n8 7 9"結果は

2 1 3
5 4 6
8 7 9

スクリプトが機能した後、結果は次のようになります。

1 2 3
4 5 6
7 8 9

PS私はawkで配列をソートすることが可能だと思いましたが、残念ながらそうするのに十分な時間がありませんでした。

答え4

ファイルがスペースで区切られたxy.datであるとします。

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

私のテストデータは数値的に昇順だったので、精神的にsort -nrを使って降順にし、どの程度効果を見ました。

設定可能にするには、ソートフラグを引数として渡すと、昇順(なし)と降順 -r(逆順)だけでなく、-n(数値)なども許可されます(参照:)sort --help。設定したいもう1つは区切り文字です。スペース/タブ/セミコロン/カンマ?たぶん、正規表現グループは"[ \t]"スペースやタブを表現するのが好きですか?では、出力は何に使用されますか?ファイル名をハードコードしたくありませんが、プログラムをフィルタとして使用してください。簡単な方法は次のとおりです。

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

移動する:

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 

--(アルファベット順:10 11 9)、逆順(9 10 11)、数字(11 10 9)など、デフォルトで並べ替えられている方法を確認してください。

主にスペース、タブなどをマスクする方法を文書化すると便利です。

関連情報