在Hash of Hash中搜索重复项

时间:2014-03-25 18:02:26

标签: perl multidimensional-array hashmap

我无法在脑海中解决这个问题,对我来说太过分了,也许有人可以帮助我:

@Hosts = ("srv1","db1","srv2","db3","srv3","db3","srv3","db4","srv3","db5");
my $count = @Hosts;
$count= $count / 2;

my %hash;
$i = 0;
$ii = 1;
$j = 0;
$jj = 0;

while ($jj < $count) {
$hash{$j}{$Hosts[$i]} = $Hosts[$ii];

$i = $i + 2;
$ii = $ii +2;

$j++;
$jj++
}

print Dumper(\%hash);

输出:

$VAR1 = {
     '4' => {
               'srv4' => 'db3'
             },
      '1' => {
               'srv2' => 'db3'
             },
      '3' => {
               'srv3' => 'db3'
             },
      '0' => {
               'srv1' => 'db1'
             },
      '2' => {
               'srv3' => 'db3'
             }
      '5' => {
               'srv3' => 'db5'
             }
    };

我知道这个丑陋的代码,我不知道如何做得更好,我需要做的是找到双服务器和双dbs,并将重复的位置和字符串放在一个类似的数组中,我想生成一个Nagvis地图文件。

Icinga Config文件包含如下所示的成员字符串:

members srv1, db1, srv2, db3, srv3, db3, srv3, db3, srv4

它有对服务器,db,server,db,这是Nagvis配置的一个示例:

define host {
object_id=5e78fb
host_name=srv1
x=237
y=122
}

define service {
object_id=30646e
host_name=srv1
service_description=db1
x=52
y=122
}

define host {
object_id=021861
host_name=srv2
x=237
y=217
}

define service {
object_id=a5e725
host_name=srv1
service_description=db2
x=52
y=217
}

提前致谢

1 个答案:

答案 0 :(得分:2)

您需要准确说明您想要的内容。你的描述很难说清楚。

并且,您的代码状况非常糟糕。缩进循环和if语句如下:

while ($jj < $anzahl) {
    $hash{$j}{$Hosts[$i]} = $Hosts[$ii];

    $i = $i + 2;
    $ii = $ii +2;

    $j++;
    $jj++
 }

使您的代码更容易理解。您还使用通用名称。 @array中存储了哪些数据?它是一个系统列表。称之为@systems$i$jj假设代表什么?你想要$hash{$j}{$Hosts[$i]}代表什么?

您应 始终,始终 将以下行添加到您的计划顶部:

use strict;
use warnings;

如果您use strict,则必须使用my 声明所有变量。这样可以确保您不会在一个地方执行@array而在另一个地方执行@Hosts。这两行将捕获大约90%的错误。


我不知道您是否需要连接到各种服务器的所有数据库系统的列表,或者您是否需要连接到数据库系统的各种服务器的列表。因此,我会给你们两个。

我猜你的@array是一个列表中所有机器和数据库的列表:

use strict;
use warnings;
use feature qw(say);   # Allows me to use "say" instead of "print"
use Data::Dumper;

my @systems = qw(      # The qw(...) is like putting quotes around each word.
    svr1  db1          # A nice way to define an array...
    srv2  db3
    srv3  db3
    srv3  db4
    srv3  db5
);

my %db_systems;       # Database systems with their servers.
my %servers;          # Servers with their database systems.


for (;;) {            # Loop forever (until I say otherwise)
    my $server   = shift @systems;

    #
    # Let's check to make sure that there's a DB machine for this server
    #

    if ( not @systems ) {
       die qq(Cannot get database for server "$server". Odd number of items in array);
    }

    my $database = shift @systems;

    $servers{$server}->{$database}    = 1;
    $db_systems{$database}->{$server} = 1;
    last if not @systems;    # break out of loop if there are no more systems
}

say "Servers:" . Dumper \%servers;
say "Databases: " . Dumper \%db_systems;

这会产生:

Servers:$VAR1 = {
        'srv3' => {
                    'db4' => 1,
                    'db3' => 1,
                    'db5' => 1
                    },
        'svr1' => {
                    'db1' => 1
                    },
        'srv2' => {
                    'db3' => 1
                    }
        };

Databases: $VAR1 = {
        'db4' => {
                    'srv3' => 1
                },
        'db3' => {
                    'srv3' => 1,
                    'srv2' => 1
                },
        'db5' => {
                    'srv3' => 1
                },
        'db1' => {
                    'svr1' => 1
                }
        };

这接近你想要的吗?


附录

  

嗨,这是有效的!!现在我需要了解如何访问值以在我的文件中打印它们。这个散列哈希的东西对我来说是个不错的选择。谢谢你的快速帮助!

您需要阅读References上的Perl教程和参考文献中的Perl Reference Page

在Perl中,所有数据都是标量,这意味着变量会讨论单个值。在其他编程语言中,您有结构或记录,但不是Perl。

即使数组和散列也只是各个数据位的集合。当你需要更复杂的东西时会发生什么?

引用是另一个Perl数据结构的内存位置。您可以引用标量变量,例如$foo,但在大多数情况下,这对您没有好处。这有用的地方是你有一个指向数组或哈希的引用。这样,您可以使用更复杂的结构来表示此数据。

想象一下包含十个项目的数组($foo[0]$foo[9])。数组中的每个条目都指向另一个包含十个项目的数组。现在这里引用了101个单独的数组。我们可以将它们视为单一结构,但记住它们是独立的数组非常重要。

我在$foo[0]处引用了一个数组。如何访问阵列本身?我执行所谓的取消引用。为此,我在前面使用右侧 sigil 的花括号。 (sigil是您在Perl变量前面看到的$@%

$foo[0];                   # Reference to an array
my @temp = @{ $foo[0] };   # Dereferencing.
my $temp[0];               # Now I can access that inner array

每次我必须取消引用它时必须使用一个临时数组是相当笨拙的,所以我不必:

$foo[0];                     # Reference to an array
my $value = ${ $foo[0] }[0]; # Getting the value of an item in my array reference

你可以看到最后有点难读。想象一下,如果我有一个项目数组的哈希哈希:

my $phone = ${ ${ ${ $employee{$emp_number} }{phone} }[0] }{NUMBER};

有点笨拙。幸运的是,Perl允许您使用一些快捷方式。首先,我可以嵌套引用并使用默认优先级:

my $phone = $employee{$emp_number}{phone}[0]{NUMBER};

我更喜欢使用->表示法:

my $phone = $employee{$emp_number}->{phone}->[0]->{NUMBER};

箭头概念更清晰,因为它将各个部分分开,它会提醒你这些是引用!。并且,不是一些复杂的结构数据结构。这有助于提醒您何时必须取消引用,例如当您使用keypoppush命令时:

for my $field ( keys %{ $employee } ) {  # Dereference the hash
   say "Field $field = " . $employee{$emp_number}->{$field}
      if ( not ref $employee{$emp_number}->{$field} );
}

查看ref以查看它的作用以及为什么我只对ref返回空字符串时打印字段感兴趣。

到现在为止,您应该能够看到如何使用->语法访问哈希哈希:

my $db_for_server = $servers{$server}->{$database};

你可以使用两个循环:

for my $server ( keys %servers } {
    my %db_systems = %{ $servers{$server} };  # Dereferencing
    for my $db_system ( keys %db_systems } {
       say "Server $server has a connection to $db_systems{$db_system}";
    }
}

或者,没有中间哈希......

for my $server { keys %servers } {
    for my $db_system ( keys %{ $servers{$server} } ) {
        say "Server $server has a connection to " . $servers{$server}->{$db_system};
    }
}

现在,请到Modern Perl获取 一书。您需要学习良好的编程技术,例如使用好的变量名,缩进,并使用 strict 警告,以帮助您编写更易于破译和支持的更好的程序。