【问题标题】:How do I invert a hash with complex values?如何反转具有复杂值的哈希?
【发布时间】:2012-08-07 19:24:14
【问题描述】:

我有这个:

%lookup = (
    'Shelf' => { storage_types => 'Flat, Default' },
    'Locker' => { storage_types => 'Valuable' },
);

我想得到这个:

%reverse_lookup = (
    'Flat' => 'Shelf',
    'Default' => 'Shelf',
    'Valuable' => 'Locker',
);

例如,我可以在测试中循环遍历存储类型,并检查子例程是否返回正确的位置。

我无法理解多列表扩展部分。

%reverse_lookup = map { split(/,\s*/, $lookup{$_}) => $_ } keys %lookup; # wrong

我想简洁地使用 map 或类似方法,而不是 foreach 循环。

【问题讨论】:

  • 如果你有%lookup = ('Locker' => { storage_types => 'Valuable' }, 'Vault' => { storage_types => 'Valuable' }),你想发生什么?

标签: algorithm perl map foreach hashmap


【解决方案1】:

你不能用单个映射来做到这一点,因为它遍历 %lookup 哈希的元素,而不是遍历内部的列表。因此,在这种情况下,您将在输出散列中拥有与源散列中相同数量的键。

但是您可以使用嵌套映射 - 首先将迭代主要哈希元素,然后将迭代内部列表。

my %lookup = (
    'Shelf' => { storage_types => 'Flat, Default' },
    'Locker' => { storage_types => 'Valuable' },
);
my %reverse_lookup = map { my $key_name = $_; map {$_ => $key_name} (split(/,\s*/, $lookup{$_}->{storage_types})) } keys %lookup;

use Data::Dumper; print Dumper \%reverse_lookup;  

附: foreach 有什么问题? :)

【讨论】:

    【解决方案2】:

    将原始哈希修改为这样可能更容易:

    %lookup = (
        'Shelf' => { storage_types => [ 'Flat', 'Default'] },
        'Locker' => { storage_types => ['Valuable'] },
    );
    

    然后

    %reverse_lookup = map {
           my $key = $_; 
           #$_ => $key foreach @{$lookup{$key}};
           map { $_ => $key } @${lookup{$key}};
        } keys %lookup;
    

    【讨论】:

    • 作者想要没有 foreach 的解决方案 :)
    【解决方案3】:

    如果您只对storage_types 感兴趣并且希望您有不可读的代码,您可以尝试:

    %reverse_lookup = map { my $k = $_; map { $_ => $k } split /,\s*/, $lookup{$_}{storage_types} } keys %lookup;
    

    【讨论】:

      【解决方案4】:

      事实证明你可以用一张地图做到这一点,只要你不介意在 void 上下文中无用地使用地图(甚至比这更愚蠢的事情):

      map { @reverse_hash{split /,\s*/, $lookup{$_}} = ($_x100) } keys %lookup;
      

      不过,它很简洁。它甚至可以工作!

      【讨论】:

      • 如果该列表包含超过 100 个元素怎么办? ;)
      • @mvf,答案很简单:只需将 100 替换为 1000 或 10,000……使用这种方法可以浪费的内存没有限制! (实际上,说真的,我想知道 x 运算符是否真的创建了一个重复值数组。如果解释器足够聪明,可以避免这种情况,我不会感到惊讶。)
      【解决方案5】:

      这就是我的编码方式

      use strict;
      use warnings;
      
      my %lookup = (
        Shelf => { storage_types => 'Flat, Default' },
        Locker => { storage_types => 'Valuable' },
      );
      
      my %reverse_lookup;
      
      while ( my ($item, $info) = each %lookup ) {
        my @types = split /,\s*/, $info->{storage_types};
        $reverse_lookup{$_} = $item for @types;
      }
      
      use Data::Dump;
      dd \%reverse_lookup;
      

      输出

      { Default => "Shelf", Flat => "Shelf", Valuable => "Locker" }
      

      【讨论】:

        猜你喜欢
        • 2015-05-10
        • 2015-04-23
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-07-09
        • 1970-01-01
        相关资源
        最近更新 更多