我有一个如下所示的矩阵:
输入:
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}
拉链两个数组,所以你得到 A 0 B 0 C 0 D 0 E 1 F 0 G 0 H 0 I 1${(j<>)...}
连接元素之间没有任何中间内容,因此它变为 A0B0C0D0E1F0G0H0I1${...//(?0|1)}
我们从中去掉?0
and1
,这样它就变成了 EI:${(s<>)...}
不进行任何分割以获得每个字母一个元素的数组: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,则将列名称复制到输出数组。然后以逗号分隔打印列名称。