Perl中数组散列的高效打印方法

Perl中数组散列的高效打印方法,perl,data-structures,hash,Perl,Data Structures,Hash,我正在编写一个脚本,其中包括打印数组散列的内容 ex(伪代码): 或 基本上,我希望能够对任意数量的键组合执行此操作,并且能够循环遍历所有可能的键/值对(或者更准确地说是键、键/数组对,因为每个值实际上是一个值数组,每个数组有2个与之关联的键),并以以下格式打印输出: 键1,键2,值1,值2,值3,…\n 例: 此代码的输出如下所示: a, b, string1,string2 c, d, string2,string1 Press any key to continue . . . 我曾考虑

我正在编写一个脚本,其中包括打印数组散列的内容

ex(伪代码):

基本上,我希望能够对任意数量的键组合执行此操作,并且能够循环遍历所有可能的键/值对(或者更准确地说是键、键/数组对,因为每个值实际上是一个值数组,每个数组有2个与之关联的键),并以以下格式打印输出:

键1,键2,值1,值2,值3,…\n

例:

此代码的输出如下所示:

a, b, string1,string2
c, d, string2,string1
Press any key to continue . . .
我曾考虑使用
each
操作符,但它似乎只适用于一维散列。(
每个
只返回一个键值对,当涉及两个键时,它不能正常工作)


如何简化此代码以遍历循环中的散列并打印所需的输出,而不管我的散列有多大?

我一直在考虑这个问题,并提出了一个可能的解决方案。如果有人有更优雅的解决方案,我很乐意看到。谢谢

以下是我提出的解决方案:

#!/usr/bin/perl

use strict;
use warnings;

# initialize hash
my %hash = ();
my $string1 = "string1";
my $string2 = "string2";

# push strings onto arrays stored in hash
push @{$hash{a}{b}}, $string1;
push @{$hash{a}{b}}, $string2;
push @{$hash{c}{d}}, $string2;
push @{$hash{c}{d}}, $string1;

# prints hash of hash of arrays in a loop :)
my @keys1 = keys %hash;
for my $key1 (@keys1) {
    my @keys2 = keys $hash{$key1};
    for my $key2 (@keys2) {
        local $" = ', ';
        print "$key1, $key2, @{$hash{$key1}{$key2}}";
        print "\n";
    }
}

system ('pause');
此解决方案不关心键的顺序,因此将以随机顺序打印

输出:

c, d, string2, string1
a, b, string1, string2
Press any key to continue . . .

我一直在考虑这个问题,并提出了一个可能的解决方案。如果有人有更优雅的解决方案,我很乐意看到。谢谢

以下是我提出的解决方案:

#!/usr/bin/perl

use strict;
use warnings;

# initialize hash
my %hash = ();
my $string1 = "string1";
my $string2 = "string2";

# push strings onto arrays stored in hash
push @{$hash{a}{b}}, $string1;
push @{$hash{a}{b}}, $string2;
push @{$hash{c}{d}}, $string2;
push @{$hash{c}{d}}, $string1;

# prints hash of hash of arrays in a loop :)
my @keys1 = keys %hash;
for my $key1 (@keys1) {
    my @keys2 = keys $hash{$key1};
    for my $key2 (@keys2) {
        local $" = ', ';
        print "$key1, $key2, @{$hash{$key1}{$key2}}";
        print "\n";
    }
}

system ('pause');
此解决方案不关心键的顺序,因此将以随机顺序打印

输出:

c, d, string2, string1
a, b, string1, string2
Press any key to continue . . .

使用
each
即使对于多层次散列也可以很好地工作,您只需确保参数是散列。下面是一个例子,说明如何做到这一点。我还演示了如何初始化您的哈希

use strict;
use warnings;
use v5.14;

my $string1 = "string1";
my $string2 = "string2";
my %hash = (
    a => { 
        b => [ $string1, $string2 ],
    },
    c => {
        d => [ $string2, $string1 ],
    }
);

for my $key (keys %hash) {
    while (my ($k, $v) = each %{ $hash{$key} }) {
        say join ", ", $key, $k, @$v;
    }
}
输出:

c, d, string2, string1
a, b, string1, string2
key1, key2, value1, value2, value3

请注意,使用
@$v
访问最里面的数组非常简单,而不是使用有点麻烦的
{$hash{$key}{$k}

使用
each
即使对于多级散列也可以很好地工作,您只需确保参数是散列即可。下面是一个例子,说明如何做到这一点。我还演示了如何初始化您的哈希

use strict;
use warnings;
use v5.14;

my $string1 = "string1";
my $string2 = "string2";
my %hash = (
    a => { 
        b => [ $string1, $string2 ],
    },
    c => {
        d => [ $string2, $string1 ],
    }
);

for my $key (keys %hash) {
    while (my ($k, $v) = each %{ $hash{$key} }) {
        say join ", ", $key, $k, @$v;
    }
}
输出:

c, d, string2, string1
a, b, string1, string2
key1, key2, value1, value2, value3

请注意,使用
@$v
访问最里面的数组非常简单,而不是使用有点麻烦的替代方法
{$hash{$key}{$k}

要打印数组的散列,可以使用
foreach
for my
在数据结构中进行迭代:

# keys of the outer hash
foreach my $oh (keys %hash) {
    # keys of the inner hash
    foreach my $ih (keys %{$hash{$oh}}) {
        # $hash{$oh}{$ih} is the array, so it can be printed thus:
        print join(", ", $oh, $ih, @{$hash{$oh}{$ih}}) . "\n";

        # or you can iterate through the items like this:
        # foreach my $arr (@{$hash{$oh}{$ih}})
        # {   doSomethingTo($arr); }

    }
}
对于所有制图爱好者,这里有一个
地图
版本:

map { my $oh = $_; 
    map { say join( ", ", $oh, $_, @{$hash{$oh}{$_}} )  } keys %{$hash{$_}}
} keys %hash;

要打印数组散列的散列,可以使用
foreach
for my
对数据结构进行迭代:

# keys of the outer hash
foreach my $oh (keys %hash) {
    # keys of the inner hash
    foreach my $ih (keys %{$hash{$oh}}) {
        # $hash{$oh}{$ih} is the array, so it can be printed thus:
        print join(", ", $oh, $ih, @{$hash{$oh}{$ih}}) . "\n";

        # or you can iterate through the items like this:
        # foreach my $arr (@{$hash{$oh}{$ih}})
        # {   doSomethingTo($arr); }

    }
}
对于所有制图爱好者,这里有一个
地图
版本:

map { my $oh = $_; 
    map { say join( ", ", $oh, $_, @{$hash{$oh}{$_}} )  } keys %{$hash{$_}}
} keys %hash;

使用递归子例程,这是最整洁的,因为它只会递归几次,所以这不是一个浪费的解决方案

use strict;
use warnings;

my %hash;
my ($string1, $string2) = qw/ string1 string2 /;

push @{$hash{a}{b}}, $string1;
push @{$hash{a}{b}}, $string2;
push @{$hash{c}{d}}, $string2;
push @{$hash{c}{d}}, $string1;

print_data(\%hash);

sub print_data {
    my ($ref, $prefix) = (@_, '');

   if (ref $ref eq 'ARRAY') {
      print $prefix, join(', ', @$ref), "\n";
   }
   else {
      print_data($ref->{$_}, "$prefix$_, ") for sort keys %$ref;
   }
}
输出

a, b, string1, string2
c, d, string2, string1

使用递归子例程,这是最整洁的,因为它只会递归几次,所以这不是一个浪费的解决方案

use strict;
use warnings;

my %hash;
my ($string1, $string2) = qw/ string1 string2 /;

push @{$hash{a}{b}}, $string1;
push @{$hash{a}{b}}, $string2;
push @{$hash{c}{d}}, $string2;
push @{$hash{c}{d}}, $string1;

print_data(\%hash);

sub print_data {
    my ($ref, $prefix) = (@_, '');

   if (ref $ref eq 'ARRAY') {
      print $prefix, join(', ', @$ref), "\n";
   }
   else {
      print_data($ref->{$_}, "$prefix$_, ") for sort keys %$ref;
   }
}
输出

a, b, string1, string2
c, d, string2, string1

听起来你需要一个嵌套循环。。。使用
map
可能有一种更难记住、可读性更低的方法;-)(当然,只为我自己说-我期待看到
map
解决方案出现在这里!):

输出:

c, d, string2, string1
a, b, string1, string2
key1, key2, value1, value2, value3
如果事情真的很复杂的话,还有一些其他的方便模块。有些需要使用散列引用,但这可能会使更简单的解决方案复杂化,或使更大、更困难的问题更容易实现

干杯


编辑:将“嵌套映射”移动到单独的答案中。

听起来您需要一个嵌套循环。。。使用
map
可能有一种更难记住、可读性更低的方法;-)(当然,只为我自己说-我期待看到
map
解决方案出现在这里!):

输出:

c, d, string2, string1
a, b, string1, string2
key1, key2, value1, value2, value3
如果事情真的很复杂的话,还有一些其他的方便模块。有些需要使用散列引用,但这可能会使更简单的解决方案复杂化,或使更大、更困难的问题更容易实现

干杯


编辑:将“嵌套映射”移动到单独的答案中。

您尚未说明为什么要打印HoHoA(数组哈希)的内容。如果出于调试目的,我会使用Data::Dumper(核心)或Data::Dump(在CPAN上)

假设您希望输出按照您的示例格式化(并且它总是且仅是HoHoA),我会使用嵌套循环:

while (my ($ok, $ov) = each %hash) {
    while (my ($ik, $iv) = each %$ov) {
        say join ',', @$iv;
    }
}
我不建议使用
map
。它最好用于列表转换,而不是流控制,并且使用嵌套的
map
块跟踪外部键和内部键很难,这两个块都使用
$\ucode>来处理不同的事情。因为你和G.Cito表示有兴趣看一部,所以,这里是:

say foreach map {
    my $o = $_;
    map {
        my $i = $_;
        join ',', $o, $i, @{$hash{$o}{$i}}
    } keys %{$hash{$o}};
} keys %hash;

您还没有说明为什么要打印HoHoA(数组散列的散列)的内容。如果出于调试目的,我会使用Data::Dumper(核心)或Data::Dump(在CPAN上)

假设您希望输出按照您的示例格式化(并且它总是且仅是HoHoA),我会使用嵌套循环:

while (my ($ok, $ov) = each %hash) {
    while (my ($ik, $iv) = each %$ov) {
        say join ',', @$iv;
    }
}
我不建议使用
map
。它最好用于列表转换,而不是流控制,并且使用嵌套的
map
块跟踪外部键和内部键很难,这两个块都使用
$\ucode>来处理不同的事情。因为你和G.Cito表示有兴趣看一部,所以,这里是:

say foreach map {
    my $o = $_;
    map {
        my $i = $_;
        join ',', $o, $i, @{$hash{$o}{$i}}
    } keys %{$hash{$o}};
} keys %hash;
我要求它:-(…一个“嵌套映射”(??)

输出:

value1
value2
value3
NB:我认为科技