同じ列値を削除

同じ列値を削除

非常に大きなファイルがあり、列の値が9の場合は削除したいと思います。

サンプル:

私のファイルの値は次のとおりです

1 5 8 3 5 9 5 7 6 9
2 5 7 4 2 9 7 6 3 1
5 9 7 4 1 9 5 7 9 1

すべての行から値が9の列を削除したいです(列サイズが大きすぎて、最初の列= 9、2番目の列= 9...などを確認できません)。動的スクリプトが必要です。

出力は次のようになります。

1 5 8 3 5 5 7 6 9
2 5 7 4 2 7 6 3 1
5 9 7 4 1 5 7 9 1

私は新しい人で、たくさん試してみましたが、正しく理解していませんでした。

どうすればいいですか?

ご協力ありがとうございます

答え1

Pythonでは:

#! /usr/bin/env python3

import sys
# Get the numbers
numbers = [[int(x) for x in line.strip().split()] for line in sys.stdin] 
# Get indexes of 9 in sets for each row
index_9 = (set(x for x, num in enumerate(line) if num == 9) for line in numbers)  

common_column = next(index_9).intersection(*index_9)

for line in numbers:
    print(' '.join((str(num) for x, num in enumerate(line) if x not in common_column)))

答え2

このawk方法は、各行に同じ数のフィールドがあると仮定します(質問に提供されている例に示すように)。また、空のフィールドがないと仮定します。

cat <<EOF >file
1 5 8 3 5 9 5 7 6 9
2 5 7 4 2 9 7 6 3 1
5 9 7 4 1 9 5 7 9 1
EOF

awk '{ for (c=1; c<=NF; c++) a[NR,c]=$c }
 END { for (c=1; c<=NF; c++) { 
         vc="" # values in column
         for (r=1; r<=NR; r++) { 
           vc = vc " " a[r,c]  }
         if ( ! gensub( /[9 ]/,"","g",vc) ) {
           for (r=1; r<=NR; r++) {
             a[r,c] = "" } }
       }
       for (r=1; r<=NR; r++) {
         for (c=1; c<=NF; c++) {
           if ( a[r,c] ) printf a[r,c]" " } 
         print "" }
     }' file

# output
1 5 8 3 5 5 7 6 9 
2 5 7 4 2 7 6 3 1 
5 9 7 4 1 5 7 9 1

答え3

多くのストレージスペースを必要としないbash / GNU coreutilsを使用する可能な方法は次のとおりです。

  1. cutファイルを列ごとに記録し、全体が9で構成されていない列のインデックスを記録します。ファイルに含まれている列の数(この場合は10)を知っている場合は簡単です。

    for ((i=1;i<11;i++)); do 
      [[ $(cut -d' ' -f${i} file | sed '/^9$/d' | wc -l) -eq 0 ]] || a+=($i)
    done
    

    (9をすべて削除した後、全体が9で構成された列のみ長さが0であるという事実を利用)

  2. 保持する列のリストを追加のcutコマンドに渡し、変更を使用してIFS配列をカンマ区切りリストに変換します。

    (IFS=, ; cut -d' ' -f"${a[*]}" file)
    

あなたのバージョンがcutこの--complementフラグをサポートしている場合は、次の列を記録できます。する以下を除くすべての9とcutすべての項目が含まれます。

    for ((i=1;i<11;i++)); do
      [[ $(cut -d' ' -f${i} file | sed '/^9$/d' | wc -l) -eq 0 ]] && a+=($i)
    done

    (IFS=, ; cut -d' ' --complement -f"${a[*]}" file)

答え4

質問の情報に基づいて現在把握できる内容は次のとおりです。

awk '{for (i=1; i<NF; i++){ a[i]+=$i; b[i]=b[i]" " $i}} END{for (i=1; i<NF; i++) if (a[i]/NR!=9) {printf "%s\n", b[i]}}' same-column-values

この関数はファイル全体を繰り返し、合計を変数「a」として計算し、その値をインデックス配列「b」に追加します。ファイルが完全に読み取られた後、合計配列が繰り返され、合計をレコード数(NR)で割った値が9に等しくない場合、配列 "b"の対応する行が印刷されます。

これは私に出力を与える 1 2 5 5 5 9 8 7 7 3 4 4 5 2 1 5 7 5 7 6 7 6 3 9

欠点は、出力を上から下に読み、上から下に、左から右に変換する必要があることです。

または、次のコマンドを使用して、値9のみを含む列のリストを取得できます。

awk '{for (i=1; i<NF; i++){ a[i]+=$i; b[i]=b[i]" " $i}} END{for (i=1; i<NF; i++) if (a[i]/NR==9){print i; }}' same-column-values

関連情報