Perl 分别检查两列中的重复值
这是我的输入文件:Perl 分别检查两列中的重复值,perl,awk,Perl,Awk,这是我的输入文件: Region_1 Region_1276 区域2区域47 地区3地区50 地区1地区14 地区50地区1 地区27地区4 地区12地区4 这是我想要的输出: Region_1 Region_1276 Common_0 区域2区域47公共区域1 区域3区域50公共区域2 区域1区域14公共区域0 区域50区域1公共区域3 区域27区域4公共区域4 区域12区域4公共区域4 目标:我想为输入中的每一行添加一个具有唯一ID的新列。问题是,有时列1有一个重复的值,在我的示例中,列
Region_1 Region_1276
区域2区域47
地区3地区50
地区1地区14
地区50地区1
地区27地区4
地区12地区4
这是我想要的输出:
Region_1 Region_1276 Common_0
区域2区域47公共区域1
区域3区域50公共区域2
区域1区域14公共区域0
区域50区域1公共区域3
区域27区域4公共区域4
区域12区域4公共区域4
目标:我想为输入中的每一行添加一个具有唯一ID的新列。问题是,有时列1有一个重复的值,在我的示例中,列1中的“Region_1”有两行。因此,这两行的ID必须相同(输出中的公共值为0)。第二列也是如此。如果列2有重复的值,则ID必须相同(公共_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++}}'
这不好,因为它只计算column1,而且我没有得到print column2。如果您将其放入.awk中
{
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
你会得到想要的结果
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
使用
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";
}
因为它将区域1与单个列表相匹配。这是否意味着您有两个列表
例如:
一般来说,这不能线性完成,需要建立一个图表 例如,如果我有
区域A区域B
区域C区域D
那么从表面上看,我有两个独立的记录,您得到的解决方案应用了两个不同的ID。但如果我有
区域C区域B
然后,这将统一前面的两个记录,并且需要为它们提供相同的ID
下面是一个使用该模块的解决方案。我已将上述情况添加到示例数据的末尾,以证明它按预期工作。如果您不需要按照输入数据的顺序分配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
如果第1列和第2列都有相同的值怎么办?你是什么意思?例如,另一行包含区域5000\t区域5000?这种情况是“正常”情况。一般来说,这不能线性完成,需要建立一个图表。例如,如果我有
Region\u 1 Region\u 2
然后是Region\u 3 Region\u 4
,那么在它的表面上,我有两个独立的记录,您得到的解决方案应用了两个不同的ID。但是如果我有Region\u 3 Region\u 2
,那么这就统一了前面的两个记录,并且它们需要得到相同的结果。我们的期望输出有记录五-第2列中的Region\u 1
-在与第1列中的记录一不同的组中-第1列中的Region\u 1
。请确认这是正确的,但这不是评估第2列。检查输出的最后两行,必须具有相同的公共_编号。确定。只需使用$2变量更改b哈希。现在是:)这个/=
做什么?条件赋值/
测试它是否未定义,如果未定义,则赋值。非常类似于|
,但处理0
和'
的边缘情况有所不同。这就是我在解决方案中描述的问题。在分配组之前,必须将所有数据读入内存
#!/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
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