非常に大きなファイルがあり、列の値が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を使用する可能な方法は次のとおりです。
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であるという事実を利用)
保持する列のリストを追加の
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