【问题标题】:Hashing multiple values to a key in perl在perl中将多个值散列到一个键
【发布时间】:2015-05-24 03:35:33
【问题描述】:

我正在读取一个单词文件,如果它们是字谜,我需要将它们散列到一个键上。因此,如果我用 dog 阅读,我会将这个词排序为 dgo。这将是我的关键。所以我读到了上帝这个词,它也会被排序为 dgo 并且它们都应该散列到同一个键。

这是我正在尝试的,但我不确定我是否正确执行此操作。

    if(exists $hash{$string})
    {
            @values2 = $hash{$string};
            push @values2, $original; 

            for my $word (@values2)
            {
                print $word."\n";
            }
            #print "Hello";
    } 

    else
    {
         @values = ();
        $hash {$string} = @values;  
        push @values, $string; 
    }   
}

所以$string 是我的排序词,关键。因此,如果密钥不存在,我会在该密钥处为我的 $hash 创建一个新数组。然后我将原始单词推入数组。但如果密钥已经存在,我会从哈希中获取数组并推送或添加下一个单词。

但这不能正常工作。我不能这样做吗?

【问题讨论】:

    标签: arrays perl hash hashmap key-value


    【解决方案1】:

    基本的 Perl 数据结构是关于单个值的。变量$foo 只能存储一个值。数组@foo 可以存储单个 值的数组。哈希 %foo 有一个指向 single 值的键。

    如果您需要更多(例如指向多个值的键),您需要了解Perl References。 Perl 引用是一种 Perl 数据结构(例如散列或数组),其中每个条目指向的不是单个值,而是另一个结构。

    在您的情况下,您希望您的密钥(单词dgo)指向包含这些字母的单词的数组

    想象一下这样的事情:

    my @dgo_words = qw(dog dgo god gdo odg ogd);   # All possible combinations
    $words{dgo} = \@dgo_words;   # The '\' means this is a reference to @dgo_words
    

    现在,words{dgo} 指向数组@dgo_words引用。如果 dereference 引用(通过在变量上放置正确的前缀),我可以回到数组:

    my @array_of_dgo_words = @{ $words{dgo} };
    

    请记住,$words{dgo} 指向一个数组,将@ 放在前面可以让我访问该数组。在这种特殊情况下,花括号是可选的:

    my @array_of_dgo_words = @$words{dgo};
    

    就个人而言,我更喜欢大括号,因为它突出了这是一个参考的事实。其他人则认为消除它们使代码更易于阅读。

    如果@{ $words{dgo} } 是我的数组,我可以使用push 向数组中添加单词:

    push @{ $words{dgo} }, 'dog';
    

    现在,dog 被添加到 $words{dgo} 引用的数组中。

    这是一个简单的程序:

    #! /usr/bin/env perl
    
    use strict;
    use warnings;
    use feature qw(say);
    
    
    my %words;
    #
    # First add all the words into the correct key
    #
    while ( my $word = <DATA> ) {
        chomp $word;
        my $key = join '', sort split //, $word;
        push @{ $words{$key} }, $word;
    }
    
    for my $group ( sort keys %words ) {        # For each key in my word hash
        my @word_group = @{ $words{$group} };   # Dereference to get the list of words
        say qq(Words for group "'$group":);
        for my $word ( @word_group ) {          # This loop prints out the words
            say "    $word";
        }
    }
    
    __DATA__
    dog
    bog
    save
    god
    gob
    vase
    

    【讨论】:

      【解决方案2】:

      您需要了解的是:perl 中不存在二维数据结构。你没有数组散列,你有数组references的散列。

      这可能会导致一些非常微妙的问题。

      例如,这与您的想法不同:

      @values = ();
      $hash{$string} = @values;
      push @values, $string;
      

      它正在清空@values。但随后它在标量上下文中分配它。这意味着您正在设置:

      $hash{$string} = 0; 
      

      然后将$string 插入@values,但这与散列没有不同,因为您已将散列值设置为空数组的大小。

      同样如此:

      @values2 = $hash{$string};
      push @values2, $original;
      
      for my $word (@values2) {
          print $word. "\n";
      }
      

      永远最多只能检索一个数组引用(但如果您填充了 else 块,它甚至不是 - 它只是 0)这意味着你的 for 循环不起作用。 $hash{$key} 只能是一个值。

      如果你想设置一个哈希键到一个数组;

       $hash{$string} = [@values]; 
      

      如果你想添加元素:

       push ( @{$hash{$string}}, @values ); 
      

      如果你想提取元素;

      my @array = @{ $hash{$string} }; 
      

      你需要额外的印记,因为这就是你告诉 perl '使用引用工作'的方式。 (在某些情况下,您也可以使用-&gt; 表示法。我省略了这一点以避免混淆问题)

      【讨论】:

      • 谢谢@Sobrique。这绝对有助于我更好地理解它。所以我需要做的就是给出数组的引用,这是有道理的。但我也会这样做以进行额外练习。谢谢!
      • 我希望人们不要再声称 Perl 不支持 proper 多维数组。它绝对可以:它将它们实现为数组引用的数组。 C 通过在编译时固定行的大小并对索引进行算术来做到这一点。如果有人可以提议对 Perl 失败的多维数组进行测试,那么我会收回它。除了 Perl 代码丑陋之外,这是一个特别让我恼火的谎言,而且发现它被 Perl 支持者重复是令人沮丧的。
      • 我想我没有这么说。这当然不是我的本意。只是为了阐明实现多维结构的机制。我也同意 - 很多人说 perl 很“混乱” - 确实它可以让你摆脱更多,但你可以用任何语言编写糟糕的代码。
      【解决方案3】:

      是的,您可以这样做。但是您不能将数组存储在哈希中,您必须存储对它的引用。

      push @{ $hash{$string} }, $original;
      

      要检索数组,请取消对值的引用:

      print join ' ', @{ $hash{dgo} }; # dog god
      

      【讨论】:

      • 好的,我试过了,但它似乎不起作用。当我推 @{$hash{$string}}, $original;它似乎将所有内容散列到同一件事上。因为当我进行您提到的打印时,它会打印所有单词。就像我几乎把我的 if 中的所有东西都拿出来并添加了你提到的那行。或者那是错的?谢谢
      猜你喜欢
      • 2023-03-20
      • 2011-02-15
      • 1970-01-01
      • 1970-01-01
      • 2021-02-04
      • 1970-01-01
      • 1970-01-01
      • 2014-07-27
      • 2023-03-07
      相关资源
      最近更新 更多