我有四个以制表符分隔的文件,其中有数百万行,看起来像这样
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的编辑中,一些更精细的细节丢失了,可能导致了投票和投票结束。在编辑之后,不再清楚我当前的输出是什么,以及我想要实现的目标。我恢复了这些信息。我希望那些沮丧的选民会重新考虑。我总是试着让我的帖子尽可能清晰,并在其中投入大量时间。
答案 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",
}