使用Perl或Linux内置的命令行工具如何将一个整数映射到另一个整数?

我有两个整数的文本文件映射,用逗号分隔:

123,456 789,555 ... 

这是120Megs …所以这是一个非常长的文件。

我继续search第一列并返回第二列,例如,查找789 –returns – > 555,我需要使用常规Linux内置插件快速完成。

我现在正在做这个,每个查找过程需要几秒钟的时间。

如果我有一个数据库,我可以索引它。 我想我需要一个索引文本文件!

这是我现在正在做的事情:

 my $lineFound=`awk -F, '/$COLUMN1/ { print $2 }' ../MyBigMappingFile.csv`; 

有没有简单的方法来提高性能?

散列建议是一个经验丰富的Perler会这样做的自然方式,但在这种情况下可能不是最理想的。 它扫描整个文件,并以线性时间建立一个大而平坦的数据结构。 更糟糕的方法可能会导致最坏情况下的线性时间短路,实际上通常会更少。

我首先做了一个大的映射文件:

 my $LEN = shift; for (1 .. $LEN) { my $rnd = int rand( 999 ); print "$_,$rnd\n"; } 

在命令行上传递的$LEN为10000000,文件出来113MB。 然后我以三个实施为基准。 首先是哈希查找方法。 第二个掠夺文件,并用正则表达式扫描它。 第三行逐行读取,并在匹配时停止。 完整的实施:

 #!/usr/bin/perl use strict; use warnings; use Benchmark qw{timethese}; my $FILE = shift; my $COUNT = 100; my $ENTRY = 40; slurp(); # Initial file slurp, to get it into the hard drive cache timethese( $COUNT, { 'hash' => sub { hash_lookup( $ENTRY ) }, 'scalar' => sub { scalar_lookup( $ENTRY ) }, 'linebyline' => sub { line_lookup( $ENTRY ) }, }); sub slurp { open( my $fh, '<', $FILE ) or die "Can't open $FILE: $!\n"; undef $/; my $s = <$fh>; close $fh; return $s; } sub hash_lookup { my ($entry) = @_; my %data; open( my $fh, '<', $FILE ) or die "Can't open $FILE: $!\n"; while( <$fh> ) { my ($name, $val) = split /,/; $data{$name} = $val; } close $fh; return $data{$entry}; } sub scalar_lookup { my ($entry) = @_; my $data = slurp(); my ($val) = $data =~ /\A $entry , (\d+) \z/x; return $val; } sub line_lookup { my ($entry) = @_; my $found; open( my $fh, '<', $FILE ) or die "Can't open $FILE: $!\n"; while( <$fh> ) { my ($name, $val) = split /,/; if( $name == $entry ) { $found = $val; last; } } close $fh; return $found; } 

在我的系统上的结果:

 Benchmark: timing 100 iterations of hash, linebyline, scalar... hash: 47 wallclock secs (18.86 usr + 27.88 sys = 46.74 CPU) @ 2.14/s (n=100) linebyline: 47 wallclock secs (18.86 usr + 27.80 sys = 46.66 CPU) @ 2.14/s (n=100) scalar: 42 wallclock secs (16.80 usr + 24.37 sys = 41.17 CPU) @ 2.43/s (n=100) 

(注意我使用的是SSD,所以I / O速度非常快,也许不需要初始slurp()

有趣的是, hash实现和linebyline一样快,这不是我所期望的。 通过使用slurping, scalar可能会在传统硬盘上变得更快。

然而,到目前为止最快的是一个简单的调用grep

 $ time grep '^40,' int_map.txt 40,795 real 0m0.508s user 0m0.374s sys 0m0.046 

Perl可以很容易地读取这个输出,几乎没有任何时间拆分逗号。

编辑:没关系grep。 我误读了这些数字。

120兆不是那么大。 假设你至少有512MB的ram,你可以很容易地把整个文件读成一个散列,然后做所有的查询。

使用:

 sed -n "/^$COLUMN1/{s/.*,//p;q}" file 

这可以通过三种方式优化你的代码:1)不需要在“,”两行上分割每行。 2)您在第一次打击后停止处理文件。 3)sed比awk快。

这应该超过一半的搜索时间。

HTH克里斯

这一切都取决于数据更改的频率以及单个脚本调用过程中需要查看的频率。

如果在每个脚本调用过程中有很多查找,我会建议将文件解析为一个散列(或者如果键范围足够窄,则为数组)。

如果文件每天都在变化,那么创建一个新的SQLite数据库可能是值得的,也可能不值得。

如果每个脚本调用只需查找一个键,并且数据文件经常变化,则可以通过将整个文件变为标量(最小化内存开销),并对其进行模式匹配(而不是分析每个文件线)。

 #!/usr/bin/env perl use warnings; use strict; die "Need key\n" unless @ARGV; my $lookup_file = 'lookup.txt'; my ($key) = @ARGV; my $re = qr/^$key,([0-9]+)$/m; open my $input, '<', $lookup_file or die "Cannot open '$lookup_file': $!"; my $buffer = do { local $/; <$input> }; close $input; if (my ($val) = ($buffer =~ $re)) { print "$key => $val\n"; } else { print "$key not found\n"; } 

在我的旧的慢速笔记本电脑上,键入文件末尾:

  C:\ Temp> dir lookup.txt
 ...
 2011/10/14 10:05 AM 135,436,073 lookup.txt

 C:\ Temp> tail lookup.txt
 4522701,5840
 5439981,16075
 7367284,649
 8417130,14090
 438297,20820
 3567548,23410
 2014461,10795
 9640262,21171
 5345399,31041

 C:\ Temp> timethis lookup.pl 5345399

 5345399 => 31041

 TimeThis:已用时间:00:00:03.343 

这个例子将文件加载到一个散列(在我的系统上需要大约20秒,120M)。 随后的查找几乎是瞬间的。 这假设左列中的每个数字都是唯一的。 如果不是这种情况,那么你需要将右边的数字与左边的相同数字推到数组或其他东西上。

 use strict; use warnings; my ($csv) = @ARGV; my $start=time; open(my $fh, $csv) or die("$csv: $!"); $|=1; print("loading $csv... "); my %numHash; my $p=0; while(<$fh>) { $p+=length; my($k,$v)=split(/,/); $numHash{$k}=$v } print("\nprocessed $p bytes in ",time()-$start, " seconds\n"); while(1) { print("\nEnter number: "); chomp(my $i=<STDIN>); print($numHash{$i}) } 

示例用法和输出:

 $ ./lookup.pl MyBigMappingFile.csv loading MyBigMappingFile.csv... processed 125829128 bytes in 19 seconds Enter number: 123 322 Enter number: 456 93 Enter number: 

如果您将文件cp到/dev/shm ,并使用/ awk / sed / perl / grep / ack /任何查询映射,它会有帮助吗?

不要告诉我你正在使用一个128MB的ram机器。 🙂