이진수로 단어 목록 만들기


12

다음과 같은 행렬이 있습니다.

입력 :

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  

헤더를 나누고 단어를 숫자와 일치 시키려고했지만 실패했습니다.

답변:


12

에서 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 }

6
NR == 1 { split($0,values) }
Sundeep

그것은 두 번째 줄을 건너 뜁니다. next첫 번째 줄의 끝에 a 를 두어 후속 줄의 반대 조건을 테스트 할 필요가 없도록하십시오.
Ed Morton

1
원래 입력 텍스트에 여분의 빈 줄이 있는데, 내가 코딩 한 것으로 보입니다. 이후 수정되었으므로로 변경 NR > 2하십시오 NR > 1.
Jeff Schaller

1
"골프"팁, Sundeep에 감사드립니다! 본문의 'for'루프와 시각적 / 논리적으로 정렬되므로 명시적인 'for'루프를 선호한다고 생각합니다.
Jeff Schaller

1
@ fusion.slope, 단일 인용 인수로 전체 코드를에 전달 awk하거나 코드를 파일에 붙여넣고 다음과 같이 실행하십시오.awk -f that.script.file input-file
Jeff Schaller

6

다른 하나 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],구분자로 사용하여 헤더 배열에서 해당 인덱스 만 인쇄

4

여전히 재미를 위해 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)}우리는 스트립 ?01는 EI가되도록 그것에서를 :
  • ${(s<>)...} 문자 당 하나의 요소 배열을 얻기 위해 아무것도 분할하지 않음 : EI
  • ${(j<,>)...},-> E, I 와 함께 참여하십시오 .

이것은 단순한 bash입니다.
fusion.slope

1
@ fusion.slope, No, that 's zsh,와 다른 쉘 bash(그리고 훨씬 강력하고 나에게 묻는다면 훨씬 더 나은 디자인). bash단지의 아주 작은 부분 빌렸다 zsh의 기능을 (같은 {1..4}, <<<, **/*)없는 사람이 대부분, 여기에 언급 bash의 기능이 그렇지에서 빌린 ' ksh.
Stéphane Chazelas

3

또 다른 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

2

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로 평가되면 각 데이터 행에 대해 열 이름을 출력 배열에 복사하여 작동합니다. 그런 다음 열 이름이 쉼표로 구분되어 인쇄됩니다.


2

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'

일부 최적화를 허용하는 변환 및 색인 부분을 교체한다는 점을 제외하면 위와 동일합니다.


설명 할 수 있다면 지역 사회에 좋을 것입니다. 미리 감사드립니다
fusion.slope

1
@ fusion.slope, 편집을 참조하십시오.
Stéphane Chazelas

t1 명령으로 루프를 멋지게!
fusion.slope

1

python3

python3 -c '
import sys
header = next(sys.stdin).rstrip().split()
for line in sys.stdin:
  print(*(h*int(f) for (h, f) in zip(header, line.rstrip().split()) if int(f)), sep=",")

  ' <file
E,I
D
D
A
A,C,G
A,D,H
A,E,F,G

0

순수한 배쉬 솔루션 :

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

3
이것이 어떻게 문제를 해결하는지 설명하십시오.
Scott

그것은 독자를위한 연습으로 남아 있습니다. 기본 bash 지식 LESS="+/^ {3}Array" man bash이 있다고 가정하면 bash 배열에 필요한 모든 정보를 제공해야합니다. 유용한 설명을 추가하기 위해 답변을 자유롭게 편집 할 수 있습니다.
David Ongaro

-1
 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();
            }
        }

3
이것이 무엇을하고 어떻게 작동하는지 설명하십시오.
Scott

언어도 부탁드립니다.
fusion.slope
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.