加速foreach循环中的perl哈希和更好的算法

时间:2012-11-27 07:31:37

标签: perl hash foreach

我有2个哈希 - > %a%b。 哈希%a来自temp.txt

my %a = map{
  my $short = substr($_,12);
  $count++ => {$short => $_};
  } @a;

my %b = map {
   $_ => $_;
  } @b;

%a = (
    '1' =>  {'We go lunch' => 'We go lunch 9 pm'},
    '2' =>  {'We go break' => 'We go break 8 pm'},
    '3' =>  {'We go lunchy' => 'We go lunchy 8 pm'}
);

%b = (
    'We go lunch' => 'We go lunch',
    'We go break' => 'We go break',
    'We go lunchy' => 'We go lunchy'
);

foreach my $key (keys %a){
  foreach my $key2 (keys %{$a{$key}}){
      if(exists $b{$key2}){
      delete $a{$key}{$key2};
      delete $a{$key};
  }
  }
}

my @another;
foreach my $key ( sort {$a<=>$b} keys %a) {
   foreach my $key2 (keys %{$a{$key}}){
      $another[$count] = $a{$key}{$key2};
      $count++;
   }
}

我怎样才能加快这个?我的哈希很奇怪吗?在@another中输出temp.txt到25144行单词需要30秒。

是否有必要为%a制作哈希哈希值? 原因是我希望删除%b{$key}中的任何%a值。 我还在学习Perl,如果你们有更好的方法做到这一点,非常感谢,可能使用map和grep?更好的算法?

以前的解决方法

如果你看到每个@b都比每个@a短,但仍然在@a中。我曾尝试使用

foreach (@b) { 
my $source = $_; 
@another = grep !(/$source/i), @a;}

但仍然不起作用。我很困惑,因此在%a中出现了哈希哈希值,并从@b中创建了哈希%b,以便在@a中删除@b的每个实例值。这是奇怪的哈希。洛尔

2 个答案:

答案 0 :(得分:2)

这里有一些未知数 - 例如%b是如何构建的。 否则,请注意几点:

您应该使用另一个数组而不是%a

  my @c = map{
    { "".substr($_,12) => $_}
   } @a;

如果您已定义%b,则可以通过以下方式进一步优化:

my @another = grep !exists $b{ substr($_,12) }, @a;

希望这有帮助

另外,不要忘记在程序开头始终 use strict;use warnings;

<强>说明:

您的代码将所有内容放在%a中,遍历它并消除不应存在的内容。 我认为你可以简单地grep并且只在数组中保留所需的结果。

优化代码应该成为:

use strict;
use warning;

my %b = (
    'We go lunch' => 'We go lunch',
    'We go break' => 'We go break',
    'We go lunch' => 'We go lunch'
);

#add code that initially fills @a

my @another = grep { !exists $b{ substr($_,12) } } @a;

答案 1 :(得分:1)

看来你很困惑。首先,substr $_, 12返回字符串中第12个之后的所有字符,因此不会创建您所说的数据结构。其次,您使用散列哈希%a作为数组,因为键是序列中没有间隙的整数,并且您存储的值是一个简单的字符串对。 / p>

对我们来说,最大的问题是你没有在所有这些中解释你的目标

您希望最终得到的数组@another包含来自temp.txt的所有不以@b中的任何字符串开头的行。那是对的吗?

我会通过从数组@b构建正则表达式,并在读取文件时检查文件中的每一行来实现。

该程序演示。我已将数组@b重命名为@exclude,因为前者是变量的可怕的名称。正则表达式是通过在数组的每个元素前面加^来构建的,以将正则表达式锚定在字符串的开头,并附加\b来强制单词边界(例如,{{{ 1}}与lunch不匹配。然后使用lunchy交替运算符将所有元素连接在一起,从而生成一个匹配字符串的正则表达式,该字符串以 |中任何行开头。

之后,读取文件,检查每行与正则表达式是一个简单的问题,并将那些不匹配的行推到@exclude

请注意,就目前而言,程序从@another文件句柄读取,以便我可以在源中包含一些测试数据。您应该通过取消注释DATA行并删除第open行来更改它。

my $fh = *DATA

<强>输出

use strict;
use warnings;

#open my $fh, '<', 'temp.txt' or die $!;
my $fh = *DATA;

my @exclude = (
  'We go lunch',
  'We go lunchy',
  'We go break',
);

my $exclude_re = join '|', map "^$_\\b", @exclude;

my @another;
while (my $line = <$fh>) {
  chomp $line;
  push @another, $line unless $line =~ $exclude_re;
}

print "$_\n" for @another;

__DATA__
We go breakfast 6 am
We go lunch 9 pm
We go break 8 pm
We go lunchy 8 pm
We go supper 7 pm