散列到字符串到数组,并使用DB_File模块

时间:2016-03-01 17:42:01

标签: arrays database perl hash

我有四个以制表符分隔的文件,其中有数百万行,看起来像这样

WRPPI   smain   hd%ww_mod%oti_obj2%vnw_vc%cp
WRUEA   smain   hd%_mod%_mod%pp_mod%pp_predc%ppart_su%
WSUEA   smain   hd%ww_mod%advp_obj2%vg
WRPPI   smain   hd%ww_mod%bw_mod%np_mod%pp_mod%pp_predm%cp_su%np
WRPPI   ssub    hd%vnw_predc%vz_su%ww
WSUEA   smain   hd%ww_svp%vnw_vc%svan
WSUEA   smain   ld%pp_mod%bw_mod%bw_mod%pp_mod%ww_su%spec
WSUEA   ppart   mod%bw_mod%n_mod%np_obj2%np_su%

我想创建一个数组哈希,重点是高效的处理和访问,可以使用DB_File模块保存在磁盘上。

我无法访问其他模块 - 仅限DB_File和默认的Perl v5.10模块。

编辑似乎最好的方法需要额外的模块,所以我想我可以允许它。我将不得不联系我们的IT人员。因此允许使用其他模块,但请将其保持在最低限度。

散列键是前两列的串联,相应的值是第三列的值数组。例如

'WRPPIsmain' => [
    'hd%ww_mod%oti_obj2%vnw_vc%cp',
    'hd%ww_mod%bw_mod%np_mod%pp_mod%pp_predm%cp_su%np'
]

到目前为止,我创建了一个哈希,并将连接作为我想要的键,但是一系列以制表符分隔的值。但我可以想象,当访问哈希时,这根本就没有效率,特别是当连接大量值时该字符串可能很长。

因此,我没有上面的预期输出,而是有一个以制表符分隔的字符串。

'WRPPIsmain' => 'hd%ww_mod%oti_obj2%vnw_vc%cp    hd%ww_mod%bw_mod%np_mod%pp_mod%pp_predm%cp_su%np'

这是我目前的代码

#!/usr/bin/perl

use strict;
use warnings;

use DB_File;

# Convert files in directory to DBM file so it
# can be used as a hash.
# COMPONENT.CAT => bfpattern1   bfpattern2  ...

# arg1: directory where overview files are stored

# perl basexcontent2db.pl contents;

tie my %HASH, "DB_File", '/some/path/content.db',
    or die "Cannot open DB_File: $!";

my $path = shift(@ARGV);    # e.g. some/path/
opendir( DIR, $path );

while ( defined( my $file = readdir(DIR) ) ) {

    next if $file =~ /^\.\.?$/;

    print STDERR "\nProcessing $file\n";
    open( FILE, "$path/$file" ) or die "Cannot open file $path/$file";

    my $linenr = 0;

    while (<FILE>) {
        $linenr++;
        print STDERR "$linenr\r";
        chomp;

        my ( $comp, $cat, $bf ) = split(/\t/);
        my $compcat = $comp . $cat;

        if ( $HASH{$compcat} ) {
            $HASH{$compcat} .= "\t$bf";
        }
        else {
            $HASH{$compcat} = $bf;
        }
    }

    close(FILE);
}

closedir(DIR);

untie %HASH;

如何将此转换为从字符串到数组的哈希,而不会失去将其作为哈希保存到磁盘的能力,而哈希又可以被另一个脚本访问?

还请提供一个示例,说明如何访问值的所有键。

最好我想要一些简单的访问,例如

tie my %BFHASH, "DB_File", '/some/path/scripts/content.db'
    or die "Cannot open database file: $!\n";

my @dbases = $BFHASH{'WRPPIsmain'};

要求:将数据处理到哈希数据库(或其他)并不重要,但访问和信息检索应该非常快。可以同时访问数据库多次,但这种情况不会经常发生。此外,一旦创建,数据库将永远不会更改。 SQL是一个选项,特别是如果它是性能方面最好的选择,但我在这个领域没有经验。如果您的答案包含SQL,请提供有关如何从Perl脚本访问该数据库的详细信息。

注意:似乎在@Borodin的编辑中,一些更精细的细节丢失了,可能导致了投票和投票结束。在编辑之后,不再清楚我当前的输出是什么,以及我想要实现的目标。我恢复了这些信息。我希望那些沮丧的选民会重新考虑。我总是试着让我的帖子尽可能清晰,并在其中投入大量时间。

1 个答案:

答案 0 :(得分:0)

只需push到数组引用,autovivificaiton将处理其余部分。 You can't store complex data structures with DB_File,由于您因任何原因无法使用任何其他模块,因此您需要使用您选择的分隔符创建简单的字符串值(在此示例中为,)。

use strict;
use warnings;

use Data::Dump;

my %data;

while (<DATA>) {
    my @fields = split;
    my $key = join('', @fields[0, 1]);
    push(@{$data{$key}}, $fields[2]);
}

for my $value (values(%data)) {
    $value = join(',', @$value);
}

dd(\%data);

__DATA__
WRPPI   smain   hd%ww_mod%oti_obj2%vnw_vc%cp
WRUEA   smain   hd%_mod%_mod%pp_mod%pp_predc%ppart_su%
WSUEA   smain   hd%ww_mod%advp_obj2%vg
WRPPI   smain   hd%ww_mod%bw_mod%np_mod%pp_mod%pp_predm%cp_su%np
WRPPI   ssub    hd%vnw_predc%vz_su%ww
WSUEA   smain   hd%ww_svp%vnw_vc%svan
WSUEA   smain   ld%pp_mod%bw_mod%bw_mod%pp_mod%ww_su%spec
WSUEA   ppart   mod%bw_mod%n_mod%np_obj2%np_su%

输出:

{
  WRPPIsmain => "hd%ww_mod%oti_obj2%vnw_vc%cp,hd%ww_mod%bw_mod%np_mod%pp_mod%pp_predm%cp_su%np",
  WRPPIssub  => "hd%vnw_predc%vz_su%ww",
  WRUEAsmain => "hd%_mod%_mod%pp_mod%pp_predc%ppart_su%",
  WSUEAppart => "mod%bw_mod%n_mod%np_obj2%np_su%",
  WSUEAsmain => "hd%ww_mod%advp_obj2%vg,hd%ww_svp%vnw_vc%svan,ld%pp_mod%bw_mod%bw_mod%pp_mod%ww_su%spec",
}