0

テキスト ファイル temp1 があり、20 を超える列があり、次のような数値が含まれているとします。

1,0,3,0,5........,
1,0,5,0,8........,
3,0,6,0,3........,
5,0,6,0,4........,
.................,

合計(合計)がゼロの列を削除したいので、残りの列を新しいファイルにリダイレクトする必要があります

つまり、たとえば、上記のように、2 番目と 4 番目の列の合計がゼロになるため、2 番目と 4 番目の列を削除して別のファイルにリダイレクトする必要があります。

誰でも私を助けることができますか?

4

4 に答える 4

2
$ cat file
1,0,3,0,5
1,0,5,0,8
3,0,6,0,3
5,0,6,0,4

$ awk -f tst.awk file
1,3,5
1,5,8
3,6,3
5,6,4

$ cat tst.awk
BEGIN{ FS="," }
{
    for (j=1;j<=NF;j++) {
        val[NR,j] = $j
        sum[j] += val[NR,j]
    }
}
END {
    for (i=1;i<=NR;i++) {
        ofs = ""
        for (j=1;j<=NF;j++) {
            if (sum[j]) {
                printf "%s%s",ofs,val[i,j]
                ofs = FS
            }
        }
        print ""
    }
}
于 2013-04-25T15:13:19.563 に答える
1

を使用する 1 つの方法を次に示しawkます。次のように実行します。

awk -f ./script.awk file{,}

の内容script.awk:

BEGIN {
    FS=","
}

FNR==NR {
    for(i=1;i<=NF;i++) {
        if ($i != 0) {
            a[i]
        }
    }
    next
}

{
    for(j=1;j<=NF;j++) {
        if (j in a) {
            printf "%s%s", $j, (j==NF ? RS : FS)
        }
    }
}

または、ここにワンライナーがあります:

awk -F, 'FNR==NR { for(i=1;i<=NF;i++) if ($i != 0) a[i]; next } { for(j=1;j<=NF;j++) if (j in a) printf "%s%s", $j, (j==NF ? RS : FS) }' filex{,}

の内容file:

1,0,3,0,5,0
1,0,5,0,8,1
3,0,6,0,3,2
5,0,6,0,4,5

結果:

1,3,5,0
1,5,8,1
3,6,3,2
5,6,4,5
于 2013-04-25T12:07:54.610 に答える
1

awk を使用できます: (以下は見苦しいですが、読みやすいと思います。それが目標です。より良い awkist にさらに強化/縮小させます)

データがファイルにある場合/path/to/zefile:

awk -F',' '  
      FNR==NR { for (col=1;col<=NF;col++)
                   { if ($col != 0) 
                        {wewantthiscolumn[col]=1 } 
                   }
                next
              }

              { for (col=1;col<=NF;col++) 
                   { if (wewantthiscolumn[col]==1) 
                        { printf ("%s,",$col) } 
                   }
                print "" 
              }' /path/to/zefile /path/to/zefile | sed -e 's/,$//'

アイデア: /path/to/zefile /path/to/zefile で awk を起動します (したがって、2 回読み取られます)。

最初のパスで、「wewantthiscolumn」配列を作成します。この配列は、その列に 0 以外の何かがあるとすぐに「1」を含みます。「次」は、FNR (=現在のファイルの行数) == NR (=行の総数) の場合にのみこのビットを実行することを保証します。これは最初のパスでのみ当てはまります。

2 番目のパスでは (したがって、現在 NR>FNR のように 2 番目の { } に直接移動します):$col対応する を持ち、wewantthiscolumn(col)==1その後に "," が続く列の値のみを表示します (少し問題があります: 最後の列後に「、」が付きます)

次に、これを sed に渡し、「,$」ビットを取り除きます。

非常に良い方法があるかどうかはわかりません.awkでフィールドを削除できますか? 2回目のパスでフィールドcolを削除できますか?次に、結果の $0 を印刷し、それらを...OFS=','で区切るように設定する方がはるかに簡単です。,

これにより、2 番目のパスが作成されます。

 awk -F',' '  
      FNR==NR { for (col=1;col<=NF;col++)
                   { if ($col != 0) 
                        {wewantthiscolumn[col]=1 } 
                   }
                next
              }

              { for (col=1;col<=NF;col++) 
                   { if (wewantthiscolumn[col]==0) 
                        $col="DELETETHIS"
                   }
                gensub(",DELETETHIS","",g)
                gensub("DELETETHIS,","",g)
                print $0 
              }' /path/to/zefile /path/to/zefile

列が空になる可能性はないと想定したくなかったので、「DELETETHIS」を使用して、関連するフィールドのみを削除するようにしています...しかし、これは、実際には最初の方法の方が簡単であることを意味します^^:必要なフィールドのみを出力し、次に、行末の「,」を取り除きます。

于 2013-04-25T11:24:36.563 に答える
0

Pythonを使用したソリューション:

#!/usr/bin/env python

def transpose(grid):
    return zip(*grid)

def removeBlankRows(grid):
    return [list(row) for row in grid if any(map(int,row))]

grid = []
with open("input.csv") as fd:
    for line in fd:
        grid.append(line.strip().split(','))

data = removeBlankRows(transpose(removeBlankRows(transpose(grid))))

for i in data:
    print ",".join(i)

入力:

1,0,3,0,5
1,0,5,0,8
3,0,6,0,3
5,0,6,0,4

出力:

1,3,5
1,5,8
3,6,3
5,6,4

入力:

1,0,3,0,5
1,0,5,0,8
3,0,6,0,3
5,0,6,1,4

出力:

1,3,0,5
1,5,0,8
3,6,0,3
5,6,1,4
于 2013-04-25T12:02:19.967 に答える