我正在编写一个脚本,它涉及打印数组哈希散列的内容。
ex(伪代码):
my %hash = ();
$hash{key1}{key2} = ['value1', 'value2', 'value3', . . .];
或
$hash{key1}{key2} = @array_of_values;
基本上我希望能够为任意数量的键组合执行此操作,并能够遍历所有可能的键/值对(或者可能更正确地表示为键,键/数组对,因为每个值实际上是一个值数组,每个数组有2个与之关联的键),并按以下格式打印输出:
" key1,key2,value1,value2,value3 ,. 。 。\ n"
例如:
#!/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;
# print elements of hash
# (want to do this as a loop for all possible key/value pairs)
local $, = ',';
print "a, b, ";
print @{$hash{a}{b}};
print "\n";
print "c, d, ";
print @{$hash{c}{d}};
print "\n";
system ('pause');
此代码的输出如下所示:
a, b, string1,string2
c, d, string2,string1
Press any key to continue . . .
我正在考虑使用each
运算符,但它似乎只适用于一维哈希。 (each
只返回一个键值对,当涉及2个键时它无法正常工作)
如何简化此代码以遍历循环中的散列并打印所需的输出,无论我的散列有多大?
答案 0 :(得分:5)
即使对于多级散列,使用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
请注意使用@$v
到达最内层数组的简单性,而不是有点麻烦的替代@{ $hash{$key}{$k} }
。
答案 1 :(得分:4)
这对于递归子例程来说是最整洁的,因为它只会递归几次,所以它不是一个浪费的解决方案。
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
答案 2 :(得分:3)
您还没有说明为什么要打印HoHoA的内容(数组哈希值)。如果是出于调试目的,我可以使用Data :: Dumper(核心)或Data :: Dump(在CPAN上)。
use Data::Dumper qw(Dumper);
print Dumper \%hash;
或
use Data::Dump qw(pp);
pp \%hash;
假设您希望按照样本格式化输出(并且它始终只是HoHoA),我会使用嵌套循环:
while (my ($ok, $ov) = each %hash) {
while (my ($ik, $iv) = each %$ov) {
say join ',', @$iv;
}
}
我不建议使用map
。它最适合用于列表转换而不是流控制,并且使用map
块嵌套$_
块来跟踪外键和内键是不方便的。因为你和G. Cito表示有兴趣看到一个,但这里是:
say foreach map {
my $o = $_;
map {
my $i = $_;
join ',', $o, $i, @{$hash{$o}{$i}}
} keys %{$hash{$o}};
} keys %hash;
答案 3 :(得分:2)
要打印数组哈希的哈希值,您可以使用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
版本:
map { my $oh = $_;
map { say join( ", ", $oh, $_, @{$hash{$oh}{$_}} ) } keys %{$hash{$_}}
} keys %hash;
答案 4 :(得分:1)
我一直在考虑它,并想出了一个可能的解决方案。如果有人有更优雅的解决方案,我很乐意看到它。谢谢!
以下是我提出的解决方案:
#!/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 . . .
答案 5 :(得分:1)
听起来你需要一个嵌套循环...这可能是一种用map
来做这件事的方法,这个方法难以记忆且不太可读;-)(当然只对我说话 - 我期待看到map
解决方案出现在这里!):
#!perl -l
my %hash = ();
$hash{key1}{key2} = ['value1', 'value2', 'value3',];
for my $outer (keys %hash) {
for my $inner (keys $hash{$outer}) {
print join(', ', $outer, $inner, @{ $hash{$outer}{$inner} } )
}
}
<强>输出:强>
key1, key2, value1, value2, value3
如果事情真的很复杂,还有Data::Printer
,Data::Seek
,Data::Dive
以及其他一些便利模块。有些人需要使用哈希引用,虽然这可能会使更简单的解决方案复杂化,或者更容易实现更大更困难的问题......
干杯,
编辑:移动&#34;嵌套地图&#34;单独回答。
答案 6 :(得分:1)
我问了它: - ( ......一个“嵌套地图”(??)。
#!perl -l
my %hash = ();
$hash{key1}{key2} = ['value1', 'value2', 'value3',];
map{ &{ sub{
map{ print for @{$hash{$_[0]}{$_}}} keys $hash{$_} }}($_)} keys %hash;
输出
value1
value2
value3
NB:我认为从技术角度(幕后)它仍然是一个循环而且效率不高。看来如果你“调用”map
的调用并用内容map{}
包含匿名sub
({& sub { ..
位),那么你可以引用外部{{} 1}}主题值来自map
({em> ie 在@_
中,因为它们进入内部$_[0]
...但仅当它们位于列表上下文中{ {1}} ...错误(?!?)好的,我只是抓住这里。
无论如何,它起作用但看起来比它应该更麻烦 - 可能是因为它是“anti-pattern”。一个好处是它使“嵌套map
循环”看起来更简洁,更容易阅读。