쌍을 이루는 항목을 표시하는 두 개의 열이 있는 탭으로 구분된 파일이 있습니다 pairs.tsv
. 두 열의 두 값을 기반으로 세 번째 열을 만들어 항목에 그룹을 할당하려고 합니다.
그러나 경우에 따라 두 개 이상의 항목이 동일한 그룹에 속합니다. 따라서 스크립트는 행 1에서 시작하여 group01
첫 번째 쌍에 할당한 다음 나머지 행에서 열 1 또는 열 2의 두 값 중 하나가 발생하는지 확인하고 true인 경우 group01
해당 행에도 할당해야 합니다.
반복 검색을 통해 쌍이 첨부된 파일의 모든 항목이 group01
할당될 때까지 이 단계를 반복해야 합니다 group01
.
그런 다음 스크립트는 다음 줄로 진행하고, 아직 할당되지 않은 경우 그룹을 그룹에 할당한 다음 group02
, 줄 2의 열 1 또는 2에 있는 항목이 아래 줄에 나타나면 나머지 파일을 다시 확인해야 합니다. 그렇다면 그것을 할당하십시오 group02
. 그 줄을주십시오. 등.
pairs.tsv
:
a b
c d
e f
e g
h i
h j
k l
f g
m n
i j
출력 파일은 다음과 같아야 합니다.
a b group01
c d group02
e f group03
e g group03
h i group04
h j group04
k l group05
f g group03
m n group06
i j group04
답변1
이 작업은 파일을 입력하여 한 번만 수행하면 됩니다.
awk -F'\t' '{
# "groups" is an associative array containing the group numbers
# for the values in fields $1 and $2.
if (! ($1 in groups)) {
# "gc" stands for "group counter"
groups[$1] = ++gc;
}
groups[$2] = groups[$1]
printf "%s\t%s\tgroup%02i\n", $1, $2, groups[$1];
}' pairs.tsv
a b group01
c d group02
e f group03
e g group03
h i group04
h j group04
k l group05
f g group03
m n group06
i j group04
%groups
나는 또한 awk 버전과 같이 해시(연관 배열)를 사용하는 Perl 버전을 작성했습니다.그리고@pairs
각 그룹의 쌍을 유지 하려면 배열의 배열 배열(AoA - 즉, 각 요소가 다른 배열의 배열임)을 호출합니다 . 결과를 읽은 대로 인쇄하는 대신, 읽은 후 모든 입력을 인쇄합니다.
#!/usr/bin/perl
use strict;
my $gc = 1; # group counter
my %groups; # hash containing group numbers for each element
my @pairs; # array of arrays containing pairs
while(<>) {
chomp;
my ($a,$b) = split /\t/;
$groups{$a} = $gc++ unless (defined($groups{$a}));
$groups{$b} = $groups{$a};
push @{ $pairs[$groups{$a}] }, [ $a, $b ];
};
END {
for my $g (keys @pairs) {
for my $p (@{ $pairs[$g] }) {
printf "%s\t%s\tgroup%02i\n", @$p[0], @$p[1], $g;
}
};
}
@pairs 배열을 반복하기 때문에 출력은 그룹 번호를 기준으로 정렬됩니다.
$ ./group.pl pairs.tsv
a b group01
c d group02
e f group03
e g group03
f g group03
h i group04
h j group04
i j group04
k l group05
m n group06
정렬을 제외하면 두 버전의 출력은 동일합니다.
답변2
귀하의 요구 사항에 대한 한 가지 가능한 설명을 기반으로 하고 모든 Unix 시스템의 모든 쉘에서 awk를 사용합니다.
$ cat tst.awk
BEGIN { FS=OFS="\t" }
{
grp = ""
for ( i=1; i<=NF; i++ ) {
if ( $i in val2grp) {
grp = val2grp[$i]
break
}
}
if ( grp == "" ) {
grp = ++grps
}
for ( i=1; i<=NF; i++ ) {
if ( !($i in val2grp) ) {
val2grp[$i] = grp
}
}
printf "%s%sgroup%02d\n", $0, OFS, grp
}
$ awk -f tst.awk pairs.tsv
a b group01
c d group02
e f group03
e g group03
h i group04
h j group04
k l group05
f g group03
m n group06
i j group04
그러나 다음 입력을 고려하십시오.
$ cat pairs2.tsv
a b
c b
d c
예상되는 출력은 다음과 같습니다.
$ awk -f tst.awk pairs2.tsv
a b group01
c b group01
d c group01
그렇지 않다면 왜 안 됩니까? 1행 b
에서 group01
then b
은 2행에도 나타나므로 마찬가지로 나타나야 합니다. group01
즉 , 3행에서는 c
이미 2행 에 있으므로 3행 전체( )도 와 연관되어 있습니다 .group01
c
group01
d
group01