【问题标题】:Pulling out sequences of hash values in Perl在 Perl 中提取哈希值序列
【发布时间】:2016-02-23 18:36:49
【问题描述】:

我有两个哈希:

1) %redundant_text 将文档中关键短语的起始位置作为哈希键,以每个关键短语的长度作为值。

2) %itter_w 将文档中每个单词的序号作为其键(1、2、3 等),对应的单词作为每个键的值。

我想通过从 %itter_w 中提取分配给由 %redundant_text 散列的元素确定的开始位置和结束位置之间的键的所有值(单词)来从文档中创建一个关键短语数组。下面的代码成功地做到了这一点,但是非常非常慢。关于如何构建此代码以最大限度地提高输出生成过程的速度的任何想法?

my @redundant_text ;
my @all_redundant_text ;

foreach my $key (keys %redundant_text) {
    my $start_position = $key  ;
    my $end_position = $key + $redundant_text{$key}+10 ;
    foreach my $word (sort {$a<=>$b} keys %itter_w) {
        next if (($word < $start_position)||($word>$end_position)) ;
        push (@redundant_text, $itter_w{$word})
    }
    ### Blanking out the redundant text array. ###
    my $redundant_sequence = join(' ', @redundant_text) ;
    @redundant_text = () ;
    push (@all_redundant_text, $redundant_sequence) ;
}

【问题讨论】:

  • 我不完全遵循您正在尝试做的事情,但您的方式似乎非常复杂。你能准确地解释什么你想做什么而不是你想怎么做吗?
  • 不确定我是否理解正确,但如果itter_w 在其位置上包含keyed 的每个单词,那么数组不应该比itter_w 的散列更适合
  • 您能否为%redundant_text%itter_w 提供一个合理的值。
  • 我想在文档中创建一组关键短语,其中“关键短语”是根据它们是否包含在文本中其他地方找到的冗余术语来识别的。所以我有一个哈希(%redundant_text),其中每个元素的形式为(x,y),其中 x 是文档中的第 n 个单词(要提取的冗余短语的起点),y 本质上是冗余短语中的单词。我正在使用这两个数据点来识别要提取的原始文档中的单词序列。

标签: perl sorting join hash


【解决方案1】:

这会快得多。以下是主要变化:

  • 排序一次的长度列表,而不是每个短语一次。 [mob 的第二种解决方案也是如此]
  • 只查找所需数量的单词,而不是遍历所有单词。 [mob 第一个解决方案的更好版本]
  • 单词从散列复制到一个数组中,以便更快地查找。

use strict;
use warnings;
use feature qw( say );

# Formerly known as %itter_w.
my %words_by_index = (
   0 => "I",        5 => "array",     10 => "the",          15 => "the",   
   1 => "want",     6 => "of",        11 => "document",     16 => "values",
   2 => "to",       7 => "key",       12 => "by",           17 => "words",
   3 => "create",   8 => "phrases",   13 => "extracting",   18 => "from",
   4 => "an",       9 => "from",      14 => "all",          19 => "itter_w",
);
# Formerly known as %redundant_text.
my %phrase_lengths_by_offset = (2=>3, 10=>4);

# Sort before the loop, and convert to a more-efficient array.
my @words = map { $words_by_index{$_} } sort { $a <=> $b } keys(%words_by_index);

my @phrases;
for my $offset( sort { $a <=> $b } keys(%phrase_lengths_by_offset)) {
   my $length = $phrase_lengths_by_offset{$offset};
   push @phrases, join(' ', @words[$offset .. $offset+$length-1]);
}

say for @phrases;

输出:

to create an
the document by extracting

【讨论】:

  • 这很完美!我的代码现在快得多了。谢谢!
【解决方案2】:

一方面,由于%itter_w 在您的循环中永远不会改变,您应该只需要在循环外而不是在每次迭代中对其进行排序。

my @words = sort {$a<=>$b} keys %itter_w;
foreach my $key (...) {
   ...
   foreach my $word (@words) {
      ...
   }
   ...
}

【讨论】:

  • 是的,我看到这确实有助于加快进程!谢谢!
【解决方案3】:

另一方面,由于$word 只会在您遍历@words 时变得更大,因此您应该能够使循环短路。当$end_position 很小但$word 可以变得非常大时,这将节省大量时间:

foreach my $word (sort {$a<=>$b} keys %itter_w) {
    next if $word < $start_position;
    last if $word > $end_position;
    push (@redundant_text, $itter_w{$word})
}

【讨论】:

  • 是的,这也有帮助!当然,一旦 $word 大于结束位置,退出循环是有意义的。谢谢!
猜你喜欢
  • 2010-10-20
  • 2016-07-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-12-30
  • 1970-01-01
  • 2020-06-27
相关资源
最近更新 更多