我有text.csv文件,其中包含IP地址和具有IP地址的组。我可以轻松找到IP 10.1.1.1属于哪个组。问题是我需要找到组(具有找到的IP)也属于的所有组。假设可能有很多小组。
我尝试下面的代码来查找IP所属的组,但是我不知道如何在循环中找到其他组。让我们看看文件text.csv:
Group name,Group members
------------------------
Group1 ,Group2
Group2 ,Group3
Group3 ,10.1.1.1
Group4 ,10.1.1.1
Group5 ,Group2
到目前为止,我的代码:
my $ip = "10.1.1.1";
$csv = Text::CSV->new({ sep_char => ',' });
open(DATA, "< :encoding(iso-8859-7)", "text.csv") or die "Could not open $!\n";
while (<DATA>) {
if ($csv->parse($_)) {
@column_all = $csv->fields();
$column_name = $column_all[0];
$column_group_member = $column_all[1];
if ($column_group_member =~ /$ip/) {
$object = $column_name;
print $column_name;
}
if ($column_group_member =~ /$objectH/) {
print $column_name;
}
}
}
这将仅打印Group3,因为它具有IP 10.1.1.1
结果应为: Group3(因为它包含IP 10.1.1.1) Group2(因为它包含Group3) Group1(因为它包含Group2)
答案 0 :(得分:3)
我们想知道每个成员所属的组,因此我们将创建一个由成员键控的数组哈希(HoA),其中包含该成员(直接)所属的所有组。
push @{ $hash{$key} }, $value;
是建立HoA的常用方法。
一旦建立了此HoA,我们将确定IP地址所属的组,然后确定每个这些组所属的组,依此类推。
如果IP属于两个属于同一组的两个组(直接或其他),我们将需要过滤掉先前见过的组。
my %seen; my @unique = grep !$seen{$_}++, @values;
是过滤重复项的常用方法。
解决方案:
use strict; # ALWAYS use this.
use warnings; # ALWAYS use this.
use feature qw( say );
use Sort::Key::Natural qw( natsort ); # Optional. Can use sort or leave unsorted instead.
use Text::CSV_XS qw( ); # Faster than Text::CSV, but otherwise identical.
my $ip = "10.1.1.1";
my $qfn = "text.csv";
my $csv = Text::CSV_XS->new({
auto_diag => 2, # Die on errors.
binary => 1, # Should always have this.
});
# "DATA" already exists, and you shouldn't be using global vars.
open(my $fh, "<:encoding(iso-8859-7)", $qfn)
or die("Can't open \"$qfn\": $!\n");
my %belongs_to;
while ( my $row = $csv->getline($fh) ) { # Proper way to use $csv
my ($member, $group) = @$row;
# Add $group to the array referenced by $belongs_to{$member}.
# The array is autovivified as if we had used « $belongs_to{$member} //= []; ».
push @{ $belongs_to{$member} }, $group;
}
# Recursively determine to which groups $ip belongs.
my %groups;
my @groups;
my @todo = $ip;
while (@todo) {
my $member = shift(@todo);
# Add every group we haven't encountered yet to @groups and @todo.
my @new_groups = grep !$groups{$_}++, @{ $belongs_to{$member} };
push @groups, @new_groups;
push @todo, @new_groups;
}
@groups = natsort @groups; # Make the results more presentable.
say for @groups;
(有一些方法可以优化最后一部分,但是增益很小,在这里要更加清晰是最重要的。)