Answers:
在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 }
next
在第一行的末尾放置a ,这样您就无需为后续的行测试相反的条件。
NR > 2
为即可NR > 1
。
awk
,或将代码粘贴到一个文件并运行它awk -f that.script.file input-file
与另一个 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]
仅使用,
分隔符从标头数组中打印那些索引仍然很有趣,一个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
和1
,使其变为EI:${(s<>)...}
拆分任何内容以获得每个字母一个元素的数组:EI${(j<,>)...}
加入那些,
-> E,I。zsh
,它不同于另一个外壳bash
(功能更强大,如果您问我,它的设计也更好)。bash
只是借用了一小部分zsh
的功能(如{1..4}
,<<<
,**/*
)不是那些在这里所提到的,大多数bash
的功能,否则,从借来的ksh
。
这是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,则将列名复制到输出数组。列名然后以逗号分隔打印。
一个sed
有趣的地方:
sed '
s/ //g
1{h;d;}
G;s/^/\
/
:1
s/\n0\(.*\n\)./\
\1/
s/\n1\(.*\n\)\(.\)/\2\
\1/
t1
s/\n.*//
s/./&,/g;s/,$//'
使用GNU sed
,您可以通过以下方式使它更加清晰:
sed -E '
s/ //g # strip the spaces
1{h;d} # hold the first line
G;s/^/\n/ # append the held line and prepend an empty line so the
# pattern space becomes <NL>010101010<NL>ABCDEFGHI we will
# build the translated version in the part before the first NL
# eating one character at a time off the start of the
# 010101010 and ABCDEFGHI parts in a loop:
:1
s/\n0(.*\n)./\n\1/ # ...<NL>0...<NL>CDEFGHI becomes
# ...<NL>...<NL>DEFGHI (0 gone along with C)
s/\n1(.*\n)(.)/\2\n\1/ # ...<NL>1...<NL>CDEFGHI becomes
# ...C<NL>...<NL>DEFGHI (1 gone but C moved to
# the translated part)
t1 # loop as long as any of those s commands succeed
s/\n.*// # in the end we have "ADG<NL><NL>", strip those NLs
s/./,&/2g # insert a , before the 2nd and following characters'
稍短一点的版本,假设每行上的位数始终相同:
sed -E '
s/ //g
1{H;d}
G
:1
s/^0(.*\n)./\1/
s/^1(.*\n)(.*\n)(.)/\1\3\2/
t1
s/\n//g
s/./,&/2g'
与上述相同,除了我们交换翻译部分和索引部分,以便进行一些优化。
纯bash解决方案:
read -a h
while read -a r
do (
for i in ${!r[@]}
do
(( r[i] == 1 )) && y[i]=${h[i]}
done
IFS=,
echo "${y[*]}")
done
LESS="+/^ {3}Array" man bash
应提供bash阵列所需的所有信息。您可以自由编辑答案以添加任何有用的说明。
void Main(string[] args)
{
int[,] numbers = new int[,]
{
{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}
};
string letters = "ABCDEFGHI";
for (int row = 0; row < 7; row++)
{
for (int col = 0; col < 9; col++)
{
if (numbers[row, col] == 1)
Console.Write(letters[col]);
}
Console.WriteLine();
}
}
NR == 1 { split($0,values) }