Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/laravel/11.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Perl 分别检查两列中的重复值_Perl_Awk - Fatal编程技术网

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