답변:
에서 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
.
또 다른 awk 솔루션 :
awk 'NR==1{ split($0,a); next } # capture and print `header` fields
{ for (i=1;i<=NF;i++) # iterating through value fields `[0 1 ...]`
if ($i) { printf "%s",(f?","a[i]:a[i]); f=1 }
f=0; print ""
}' file
출력 :
E,I
D
D
A
A,C,G
A,D,H
A,E,F,G
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'
일부 최적화를 허용하는 변환 및 색인 부분을 교체한다는 점을 제외하면 위와 동일합니다.
순수한 배쉬 솔루션 :
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) }