将多个值散列到perl中的一个键

Hashing multiple values to a key in perl

我正在读取一个单词文件,如果单词是变位词,则需要将它们散列为一个键。所以如果我读狗,我把这个词排序成 dgo。这将是我的钥匙。所以我读入了 god 这个词,它也会被排序为 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 创建一个新数组。然后我将原始单词推入数组。但如果密钥已经存在,我就会从哈希中获取数组并推送或添加下一个单词。

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

是的,你可以做到这一点。但是你不能在散列中存储数组,你必须存储对它的引用。

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

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

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

你需要明白的是: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 'work with a reference' 的方式。 (在某些情况下你也可以使用 -> 符号。我省略了这个以避免混淆问题)

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

如果您需要更多(例如指向多个值的键),您需要了解 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 引用 。如果 取消引用 引用(通过在变量上放置正确的前缀),我可以返回数组:

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