ペアの項目を表示する2つの列を持つタブ区切りファイルがありますpairs.tsv
。 2つの列の2つの値に基づいて3番目の列を作成し、アイテムにグループを割り当てようとしています。
ただし、場合によっては、複数の項目が同じグループに属します。したがって、スクリプトは行1から始めてgroup01
最初のペアに割り当て、残りの行で列1または列2の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
あなたの要件の1つの可能な説明に基づいており、すべての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
そうでなければなぜならないのですか?行1b
では、group01
thenb
は行2にも表示されるため、同じように表示する必要があります。group01
つまり、3行ではc
すでに2行にあるので、3行全体( )もに関連付けられています。group01
c
group01
d
group01