2つの行列間をフィルタリングする方法は?

2つの行列間をフィルタリングする方法は?

ファイル1:

91  23  56  44  87  77
99  34  56  22  22  95
41  88  26  79  60  27
95  55  66  69  92  25

ファイル2:

pass fail pass pass pass fail
pass fail pass fail fail pass
pass pass fail pass pass fail
pass pass fail pass pass fail

各行の合計失敗トークンを合計しようとするため、これが予想される出力です。

出力:

100
78
53
91

失敗トークンの合計を得るために、file2の「fail」という単語に基づいてfile1をフィルタリングする方法を尋ねたいと思います。

答え1

私はそのような仕事のためにGNU Octaveのようなマトリックス言語を使用します。

パススルー/失敗ファイルを数値に変換するとします。たとえば、次のようになります。

sed 's/pass/1/g; s/fail/0/g' passfail > passfail.nums

これで、次のことができます。

marks    = dlmread('marks');
passfail = dlmread('passfail.nums');

for i = 1:size(marks)(1)
  sum(marks(i,:)(passfail(i,:) == 0))
end

出力:

ans =  100
ans =  78
ans =  53
ans =  91

答え2

私はを使用することが移植性に良いと思いますがawk、この作業のためには他の言語が書いて読むのがより簡単なようです。 GNU Octaveが言及されていますが、ほとんどのシステムにはプリインストールされていません。一方、ほとんどのシステムにはプリインストールされたPythonバージョンが付属しています。 Pythonのバージョンは次のとおりです。

for marks, decisions in zip(open('file1').readlines(), open('file2').readlines()):
    row_score = 0
    for mark, decision in zip(marks.split(), decisions.split()):
        if decision == 'fail':
            row_score += int(mark)
    print(row_score)

予想される出力を返します。

答え3

これが私のawkアプローチです。

awk 'NR==FNR{for(i=1;i<=NF;i++) a[NR"-"i]=$i; next} \
            {for(j=1;j<=NF;j++) if($j=="fail") b[FNR]+=a[FNR"-"j]} \
         END{for(k in b) print b[k]}' file1 file2

awkは2D配列をサポートしていないため、同じ配列インデックスに2つの数字(行とフィールド)を結合して2D配列を結合します。出力は次のとおりです

100
78
53
91

答え4

awk '
  BEGIN{ pf=ARGV[2]; ARGV[2]="" }
  { getline l <pf; split(l, a); n=0;
    for(i=1;i<=NF;i++) if(a[i]=="fail") n+=$i;
    print n }
' file1 file2
100
78
53
91

@MaximのPythonバージョンと似ていますが、他のすべての答えとは異なり、これはファイルをメモリに完全にロードするのではなく、2つのファイルを1行ずつ並列に処理します。

関連情報