在Perl中填充和搜索数组的哈希值?

时间:2015-06-23 03:44:21

标签: arrays perl hash

我正在尝试使用目录中所有文本文件中的单词填充数组的哈希值。单词用作键,而文件名用作与键关联的标量值。

我正在使用数组哈希,因为一个单词可能很容易在另一个文本文件中重复。我想填写哈希;那么我想用关键词来搜索哪些文件包含一些给定的关键词。

我的代码摘录:

# Search term(s).
my @search_terms = ("random", "searches");

opendir(DIR, $directory) or die $!;
@files = grep(/\.txt$/, readdir(DIR)) or die("you idiot");

# Create a hash table to store the words as keys and the file name. 
my %hash;

# Go through the files, grab the words, and create hash table.  
foreach my $file(@files)  {
    open(FILE,"<$file") or die $!;
    while(<FILE>){
        chomp;
        my @words = split(' ');
        # Store the key, value pairs for each file.
        # Key is the word.
        # Value is the file name.
        foreach my $word(@words)  {
            push @{$hash{$word}}, $file;
        }
    }
    close(FILE);
}

# Go through each search term.
foreach my $match(@search_terms)  {
   # If a key exists in the hash table, then we have a matched result.
   if($hash{$match})  {
        # Print the file name (scalar value for word key).
        print "$hash{$match} matched.";
        print "\n";
    }
}

似乎我可能没有正确地填充我的哈希(或者我只是不知道如何打印数组的哈希)。此外,我的匹配文件不正确。任何关于我做错的帮助都将不胜感激!谢谢!

2 个答案:

答案 0 :(得分:1)

你缺少的是perl中没有任何像数组哈希这样的东西。或者一系列哈希。数组和散列都只能包含一个值。

他们的方式perl&#39;做&#39;多维是通过参考:

my %hash;
push ( @{$hash{'fish'}}, "trout" ); 

foreach my $key ( keys %hash ) {
   print "$key $hash{$key}\n";
}

这将打印(类似):

fish ARRAY(0x2d6ed4)

这是因为$hash{$key}中的单值是对该数组的引用。然后,您需要取消引用才能访问。

E.g。

print join ( "\n", @{$hash{$key}} ); 

例如。

Data::Dumper可以帮助您了解正在发生的事情:

my %hash;
push ( @{$hash{'fish'}}, "trout" ); 

print Dumper \%hash;

打印:

$VAR1 = {
          'fish' => [
                      'trout'
                    ]
        };

要回答您的原始问题 - 稍微更改您的foreach循环:

foreach my $match (@search_terms)  {
   # If a key exists in the hash table, then we have a matched result.
   if($hash{$match})  {
        # Print the file name (scalar value for word key).
        # $hash{$match} is an array reference, so we need to de-reference:
        my @matching_files = @{$hash{$match}};
        print "$match found in:\n";
        print join ( "\n", @matching_files),"\n";
    }
}

(为了清晰起见,我已经使它变得比它需要的更冗长了 - 你可以进一步减少它)。

我还会提供一些辅助建议:

  • 开启strictwarnings。它们对于编写好的代码非常重要。
  • 不要那样使用open。请尝试改为:

    open ( my $file, "<", $filename ) or die $!; 
    while ( <$file> ) { ... }
    
  • 我更喜欢globreaddirgrep,因为您正在做的方法之一就是所有open都会失败,除非$directory也是当前工作目录。 (您需要添加文件名的路径)。 :

    foreach my $filename ( glob "$directory/*.txt" ) { ... } 
    
  • split(' ');很好,但它与split;相同。选择您认为最具可读性的。

  • 您实际上不需要做my @words = split; foreach my $word ( split ) { ...

答案 1 :(得分:0)

你很接近,只需要在每个哈希键上展开

# Go through each search term.
foreach my $match(@search_terms)  {
   # If a key exists in the hash table, then we have a matched result.
   if($hash{$match})  {
        # Print the file name (scalar value for word key).
        print "$hash{$match} matched in file(s) ";
        foreach my $elem ( @{"$hash{$match}} ) {
            print "$elem : "
        }
        print "\n";
    }
}