すべての個々のグループ項目間のペアを構成する値のリストに基づいてグループを割り当てます。

すべての個々のグループ項目間のペアを構成する値のリストに基づいてグループを割り当てます。

ペアの項目を表示する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では、group01thenbは行2にも表示されるため、同じように表示する必要があります。group01つまり、3行ではcすでに2行にあるので、3行全体( )もに関連付けられています。group01cgroup01dgroup01

関連情報