在perl中用hash编写交换键和值的最紧凑的方法

时间:2012-03-15 19:47:58

标签: perl

我想通过在perl中的散列中交换键和值来创建新的哈希。请注意,这样做是为了将重复值的键放入数组中,这与reverse不同。

我显然可以为此做一个循环。但我不确定它是否可以以紧凑的形式完成,例如使用map等。

谢谢。

2 个答案:

答案 0 :(得分:8)

你可以像这样做一个“紧凑”循环;

my %orig = # whatever
my %rev;
push @{$rev{$orig{$_}}}, $_ for keys %orig;

请注意,“反向”哈希的所有值都是带有此值的数组。

答案 1 :(得分:1)

这样的功能?

my %orig = ( 1 => 'a', 2 => 'b', 3 => 'c', 65 => 'a' );
my $new_hash = List::Util::reduce { push @{ $a->{$orig{$b}} }, $b; $a } {}, keys %orig;

出于某种原因,在hash-dereference中包含reduce调用似乎打破了& -prototype魔术,但你可以通过以下方式避免使用新变量:

%orig = %{ List::Util::reduce sub { push @{ $a->{$orig{$b}} }, $b; $a }, {}, keys %orig };

如果你想避免对%orig的内部引用,比如说原始哈希是来自其他表达式的结果,假装perl有pairlists:

%orig = %{ List::Util::reduce sub { push @{ $a->{ $b->[0] } }, $b->[1]; $a }, {},
    @{ List::Util::reduce sub { ! @$a || $#{ $a->[-1] } ? push @$a, [ $b ] : push @{ $a->[-1] }, $b; $a }, [],
        reverse %orig
    }
};

更实用的一些实用功能:

sub flatten_hashref { %{$_[0]} }
sub flatten_arrayref { @{$_[0]} }
sub pairlist { reduce { ! @$a || $#{ $a->[-1] } ? push @$a, [ $b ] : push @{ $a->[-1] }, $b; $a } [], @_ }

%orig =
    flatten_hashref
    reduce { push @{ $a->{ $b->[0] } }, $b->[1]; $a } {},
    flatten_arrayref
    pairlist
    reverse
    %orig;