Нужно найти строку в группе, затем найти все группы, к которым принадлежит одна группа (содержащая строку) - PullRequest
2 голосов
/ 08 апреля 2019

У меня есть файл 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

Результат должен быть: Группа 3 (потому что она содержит IP 10.1.1.1) Group2 (потому что он содержит Group3) Group1 (потому что он содержит Group2)

1 Ответ

3 голосов
/ 08 апреля 2019

Мы хотим знать, к каким группам принадлежит каждый член, поэтому мы создадим Hash of Arrays (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;

(Существуют способы оптимизации последней части, но выгоды минимальны, и предельная ясность здесь важнее.)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...