分别检查两列中的重复值

时间:2016-01-15 09:56:06

标签: perl awk

这是我的输入文件:

Region_1    Region_1276
Region_2    Region_47
Region_3    Region_50
Region_1    Region_14
Region_50   Region_1
Region_27   Region_4
Region_12   Region_4

这就是我想要的输出

Region_1        Region_1276     Common_0
Region_2        Region_47       Common_1
Region_3        Region_50       Common_2
Region_1        Region_14       Common_0
Region_50       Region_1        Common_3
Region_27       Region_4        Common_4
Region_12       Region_4        Common_4

目标:我想为输入中的每一行添加一个具有唯一ID的新列。问题是有时第一列有一个重复的值,在我的例子中,column1中的“Region_1”有两行。因此,这两行的ID必须相同(输出中的Common_0)。它与第二列的情况相同。如果第2列具有重复值,则ID必须相同(Common_4)。我白天一直在努力,但这是我最接近的代码,而且距离解决方案还很远:

 awk -v c=0 '{a[$1]++}END{for(x in a){if(a[x]>1){for(i=1;i<=a[x];i++){print x"\tCommon_"c}}else{print x"\tCommon_"c};c++}}'

输出我的代码:

Region_27   Common_0
Region_12   Common_1
Region_1    Common_2
Region_1    Common_2
Region_50   Common_3
Region_2    Common_4
Region_3    Common_5

这不好,因为它只评估column1,而且我没有得到print column2。

3 个答案:

答案 0 :(得分:1)

如果你把它放入a.awk

col = sys.argv[1]
db[col].find()

你做了

{
    if (a[$1])
        print $0 a[$1]
    else if (b[$2])
        print $0 b[$2]
    else {
        print $0 " common_" c
        a[$1] = b[$2] = " common_" c
        c++
    }
}

您将获得所需的结果

awk -f a.awk -v c=0 foo.txt | column -t

答案 1 :(得分:1)

使用perl我会像这样解决它:

#!/usr/bin/env perl
use strict;
use warnings;

use Data::Dumper;

my %id_for;
my $count = 0; 

while ( <> ) {
   chomp; 
   my ( $R1, $R2 ) = split; 
   my $id = $id_for{$R1} // $id_for{$R2} // $count++; 
   $id_for{$R1} //= $id; 
   $id_for{$R2} //= $id; 
   print join ( "\t", $R1, $R2, "common_".$id_for{$R1} ), "\n";

}

这并不是你想要的,因为我得到了:

Region_1    Region_1276 common_0
Region_2    Region_47   common_1
Region_3    Region_50   common_2
Region_1    Region_14   common_0
Region_50   Region_1    common_2
Region_27   Region_4    common_3
Region_12   Region_4    common_3

因为它将该区域1与单个列表进行匹配。这是否意味着你有两个名单?

E.g:

#!/usr/bin/env perl
use strict;
use warnings;

my %column_A;
my %column_B;
my $count = 0; 

while ( <> ) {
   chomp; 
   my ( $R1, $R2 ) = split; 
   my $id = $column_A{$R1} // $column_B{$R2} // $count++; 
   $column_A{$R1} //= $id; 
   $column_B{$R2} //= $id; 
   print join ( "\t", $R1, $R2, "Common_".$id ), "\n";

}

这会创建一个看起来像您想要的输出的列表:

Region_1    Region_1276 Common_0
Region_2    Region_47   Common_1
Region_3    Region_50   Common_2
Region_1    Region_14   Common_0
Region_50   Region_1    Common_3
Region_27   Region_4    Common_4
Region_12   Region_4    Common_4

答案 2 :(得分:1)

一般情况下,这不能线性完成,需要构建图表。

例如,如果我有

Region_A    Region_B
Region_C    Region_D

然后从表面上看,我有两个独立的记录,你给出的解决方案应用了两个不同的ID。但如果我那么

Region_C    Region_B

然后统一前两个记录,他们需要给出相同的ID

这是使用Graph模块的解决方案。我已将上面的情况添加到示例数据的末尾,以证明它按预期工作。如果您不需要按照输入数据的顺序分配ID,或者您希望以与输入不同的顺序输出分配,那么可以使用更简单的解决方案

use strict;
use warnings 'all';

use Graph;

my @data = <DATA>;
chomp @data;

my $g = Graph::Undirected->new(vertices => \@data, );
my @vertices = $g->vertices;

for my $i ( 0 .. $#vertices ) {

    for my $j ( $i+1 .. $#vertices ) {

        my @ri = split ' ', $vertices[$i];
        my @rj = split ' ', $vertices[$j];

        if ( $ri[0] eq $rj[0] or $ri[1] eq $rj[1]) {
            $g->add_edge($vertices[$i], $vertices[$j]);
        }
    }
}

my %group;
{
    my $n = 0;
    for my $set ( $g->connected_components ) {
        $group{$_} = $n for @$set;
        ++$n;
    }
}

my @ids;
my $n = 0;
for ( @data ) {
    printf "%-16s%-16s%-16s\n", split, $ids[$group{$_}] //= 'common_' . $n++;
}


__DATA__
Region_1    Region_1276
Region_2    Region_47
Region_3    Region_50
Region_1    Region_14
Region_50   Region_1
Region_27   Region_4
Region_12   Region_4
Region_A    Region_B
Region_C    Region_D
Region_C    Region_B

输出

Region_1        Region_1276     common_0        
Region_2        Region_47       common_1        
Region_3        Region_50       common_2        
Region_1        Region_14       common_0        
Region_50       Region_1        common_3        
Region_27       Region_4        common_4        
Region_12       Region_4        common_4        
Region_A        Region_B        common_5        
Region_C        Region_D        common_5        
Region_C        Region_B        common_5