在Perl中为哈希表创建映射

22

是否有类似于map的哈希等效物?

my %new_hash = hash_map { new_key($a) => new_val($b) } %hash;
我知道我可以通过循环遍历键。
6个回答

21

List::Pairwise声称实现了确切的语法--请参见mappgrepp。虽然我没有使用过它。

同时,您也可以这样做:

%new_hash = map { new_key($_) => new_value($hash{$_}) } keys %hash; 

如果%hash真的是一个深度嵌套的哈希表,我承认这看起来比较笨拙。在这种情况下,我更喜欢使用$temp = ...; map {...} keys %$temp


你正在给哈希赋值。假设我想创建一个哈希映射引用({ something => 42 }),并将其传递给一个函数。看起来结果是一个数组。如果我将结果分配给标量,我会得到一个哈希引用,但是当我打印它(不进行分配)时,我得到的是一个数组。也许可以详细解释一下。 - U. Windl

11

我真的看不出你在这里想做什么。“map的哈希等效”是什么意思?你可以很好地在哈希上使用map。如果你想要键,只需使用keys;例如:

@msglist = map { "value of $_ is $hash{$_}" } keys %hash    

虽然通常

say "value of $_ is $hash{$_}"  keys %hash;

很好。

如果你想要两个,那么使用整个哈希。

对于赋值,%new_hash = %old_hash有什么问题吗?

你是否有深复制的问题?那么使用Storable::dclone

如果你想让键和值在闭包中同时可用,那么使用第一个map制作一堆成对的元素:

@pairlist = map { [ $_ => $hash{$_} ] } keys %hash  

我需要看到一个例子,展示你希望使用这个东西做什么,但是目前我看不出来为什么要使用某个庞大的旧模块,而不是使用基本的Perl。


我在寻找一个比使用keys更优雅的替代方案。正如建议的那样,List::PairwiseList::Gen提供了这种方法。从来没有遇到过分配问题,所以那可能是误解。至于何时值得使用模块简化程序,我认为这是个人口味的问题。 - Tim
@Tim:List::Gen 看起来有点有趣,但我想不出为什么有人会使用 List::Pairwise,因为它以一种隐藏了实际发生情况的方式,而 map { "got $_ => $h{$_}" } keys %h 则非常明显。话虽如此,我确实经常构建有序对列表,我的意思是有序对的有序列表。 - tchrist
那个句法say String keys Hash在哪里有记录,它为什么在“keys”附近没有产生语法错误? - Armali

6
您可以像这样使用地图:
my $i = 0;
my %new_hash = map { $i ^= 1 ? new_key($_) : new_val($_) } %hash;

抱歉,我的示例只是一个特殊情况。我希望new_keynew_val是键和值的函数。(虽然这回答了我提出的问题。) - Tim

4
您可以使用我的模块List::Gen中的mapn来实现此功能:
use List::Gen 'mapn';

my %new_hash = mapn {new_key($_[0]) => new_value($_[1])} 2 => %old_hash;

mapn类似于map,但它会多接收一个参数,即列表中要遍历的元素数。在代码块内,@_数组被设置为当前的切片。


谢谢,这更加通用。 - Tim

3

$ perl -d /dev/null

  DB<2> %p = ( a=>'b', c=> 'd');                                                
  DB<5> p Dumper \%p                                                            
$VAR1 = {
          'c' => 'd',
          'a' => 'b'
        };

比如将键和值反转:

  DB<6> %q = map { ($p{$_}, $_ ) } keys %p                                      
  DB<7> p Dumper \%q                                                            
$VAR1 = {
          'b' => 'a',
          'd' => 'c'
        };

正如问题和其他答案中所看到的,我知道可以通过循环遍历键来解决。我想知道是否有另一种解决方案。(而这个解决方案是List::Pairwise。) - Tim

0

从Perl 5.20开始,核心实用程序List::Util::pairmap正好做到了这一点:

use List::Util qw(pairmap);

my %new_hash = pairmap { new_key($a) => new_val($b) } %hash;

这并不一定是最优的(因为它涉及到将哈希展开成列表再转换回去),但我相信这是使用原始 Perl 最短的方法。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接