perl - 在 Perl 中对巨大的哈希进行排序

标签 perl sorting hash

我正在分析句子中一起出现的词组的出现频率。

每组由 3 个单词组成,我们必须计算它们的频率。

示例:这是聚会的好时机,因为这是假期。

预期输出:

this is a - 2
is a good - 1
a good time - 1

等等。

我编写了一个运行良好的脚本,它打印频率并按降序对其进行排序。

它的工作原理是一次从文件中读取一行。对于每一行,它会将它们转换为小写,将其拆分为单独的单词,然后从中形成一个数组。

然后,我们从左边开始一次选择 3 个单词,并不断形成一个哈希来存储出现次数。完成后,我们移动数组中最左边的元素并重复,直到我们的数组包含超过 3 个单词。

问题已更新:

问题是我想在包含超过 1000 万行的文件上使用此脚本。

在运行一些测试后,我观察到如果输入文件中的行数超过 400K,它将无法工作。

我怎样才能让这个脚本更有内存效率?

感谢 fxzuz 的建议,但现在我想让这个脚本处理更大的文件:)

#!/usr/bin/perl

use strict;
use warnings;

print "Enter the File name: ";
my $input = <STDIN>;
chomp $input;

open INPUT, '<', $input 
    or die("Couldn't open the file, $input with error: $!\n");

my %c;

while (my $line = <INPUT>) {

    chomp $line;
    my @x = map lc, split /\W+/, join "", $line;

    while (@x>3) {

        $c{"@x[0..2]"}++;
        shift @x;
    }
}

foreach $key (sort {$c{$b} <=> $c{$a}} keys %c) {

    if($c{$key} > 20) {

        print $key." - ".$c{$key}."\n";
    }
}

close INPUT;

这很好用,它会按频率降序打印单词组。它只会打印出现次数超过 20 次的词组。

现在,我如何在包含超过 100 万或 1000 万行的文件上执行此操作?

我还在 Linux 中使用 top 命令运行此脚本时检查了 perl 的内存和 CPU 使用情况,并观察到当脚本在 400K 组成的文件上运行时,CPU 使用率达到 100%,内存使用率接近 90%行。

因此,要使其与包含 100 万行的文件一起工作是不可行的。因为perl进程会挂掉。

如何使这段代码的内存效率更高?

最佳答案

显然,您的代码编写正确并且可以运行,但前提是您的数据集不是很大。如果您有大量输入数据(并且看起来确实如此),排序阶段可能会由于内存不足而失败。如果您无法增加内存,唯一的解决方案是将数据写入磁盘 - 以文本或数据库格式。

  1. 文本格式:您可以在进入文本文件时简单地写下您的三元组,每个三元组一行。这样做会将输出大小增加 3 倍,但它仍然是可管理的。然后,您可以简单地使用命令行 gnu sort 和 uniq 工具来获得您想要的计数,如下所示:

    text2triplet.pl <input.txt | sort | uniq -c | sort -r | head -10000 (您可能希望将用于排序的输出存储到一个文件中,如果它非常大则不要通过管道传输)

  2. 数据库格式:使用 DBD::SQLite 并像这样创建表:

    CREATE TABLE hash (triplet VARCHAR, count INTEGER DEFAULT 0);

    CREATE INDEX idx1 ON hash (triplet);

    CREATE INDEX idx2 ON hash (count);

INSERT将您的三胞胎放入该表中,并增加重复项的数量。处理数据后,只需

 SELECT * FROM hash
 WHERE count > 20
 ORDER BY count DESC

然后打印出来。 然后你可以DROP您的哈希表或干脆删除整个 SQLite 数据库。

这两种方法都应该允许您扩展到几乎磁盘的大小,但数据库方法可能更灵活。

关于perl - 在 Perl 中对巨大的哈希进行排序,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13043083/

相关文章:

java - 在 html 中显示 sqlite 数据库查询

perl - 意外的参数自动激活

python - pandas .sortlevel 无法对负数进行排序

MySQL对行进行分组来查找时间差

javascript - WWW::Scripter 作为父类导致奇怪的错误消息

perl - 将简单的 Perl CGI 扩展到大容量服务器

php - 在自定义 foreach 循环中按字母顺序对结果进行排序

json - 在 redis 中存储用户配置文件的更好数据结构是什么?

hash - 使用 Redis 哈希来存储问题/答案对

ruby - 按另一个散列中的值对散​​列进行排序