バイナリで単語リストを作成する

バイナリで単語リストを作成する

次の行列があります。

入力する:

A   B   C   D   E   F   G   H   I 
0   0   0   0   1   0   0   0   1
0   0   0   1   0   0   0   0   0  
0   0   0   1   0   0   0   0   0  
1   0   0   0   0   0   0   0   0  
1   0   1   0   0   0   1   0   0  
1   0   0   1   0   0   0   1   0  
1   0   0   0   1   1   1   0   0  

各行の値1に対応する文字のリストを抽出したいと思います。

出力:

E,I 
D
D
A
A,C,G  
A,D,H  
A,E,F,G  

タイトルを分けて単語を数字に合わせてみましたが失敗しました。

答え1

存在するawk

NR == 1 { for(column=1; column <= NF; column++) values[column]=$column; }
NR > 1 { output=""
        for(column=1; column <= NF; column++)
                if($column) output=output ? output "," values[column] : values[column]
        print output }

答え2

もう一つはperl

$ perl -lane 'if($. == 1){ @h=@F }
              else{@i = grep {$F[$_]==1} (0..$#F); print join ",",@h[@i]}
             ' ip.txt
E,I
D
D
A
A,C,G
A,D,H
A,E,F,G
  • -a入力行をスペースに分割するオプション(@F配列で利用可能)
  • if($. == 1){ @h=@F }最初の行にタイトルがある場合
  • @i = grep {$F[$_]==1} (0..$#F)エントリが次の場合にインデックスを保存する1
  • print join ",",@h[@i],ヘッダー配列の対応するインデックスのみを印刷するには、区切り文字として使用してください。

答え3

それでも楽しく使うバージョンは次のとおりですzsh

{
   read -A a  &&
   while read -A b; do
     echo ${(j<,>)${(s<>)${(j<>)a:^b}//(?0|1)}}
   done
} < file
  • ${a:^b} ジッパー2つの配列なので、A 0 B 0 C 0 D 0 E 1 F 0 G 0 H 0 I 1になります。
  • ${(j<>)...}連結要素間に何もないので、A0B0C0D0E1F0G0H0I1 になります。
  • ${...//(?0|1)}EIになるように?0andを削除します。1
  • ${(s<>)...}文字ごとに1つの要素で構成される配列を取得するために分割せずに:EI
  • ${(j<,>)...}参加している方,- > E、I。

答え4

Perlソリューションは次のとおりです。

use strict;

my @header = split /\s+/, <>;
<>; ## Skip blank line
while (<>) {
    my @flags = split /\s+/;
    my @letters = ();
    for my $i (0 .. scalar @flags - 1) {
        push @letters, $header[$i] if $flags[$i];
    }

    print join(',', @letters), "\n";
}

ヘッダー列を配列に読み込み、各データ行に対して一致するデータ列が true と評価されると、列名が出力配列にコピーされます。次に、カンマで区切られた列名を印刷します。

関連情報