次の行列があります。
入力する:
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になるように?0
andを削除します。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 と評価されると、列名が出力配列にコピーされます。次に、カンマで区切られた列名を印刷します。