如何在长文本列表中打印第1行,第10行,第20行...(不是数组索引)编号。 当然,以下内容不起作用:
for(my $i=0; $i<=$arr_size; $i+=10){
print $arr[$i],"\n";
}
非常感谢提前。
答案 0 :(得分:10)
如果您正在阅读文件句柄:
while (my $line = <$fh>) {
if ($. == 1 or not $. % 10) {
print $line;
}
}
如果你的标量包含许多行,如:
my $s = join "", map { "$_\n" } "a" .. "z";
然后,您可以通过在open
期间传递对它的引用来将标量视为文件:
open my $fh, "<", \$s
or die "could not open in-memory file: $!";
然后使用上面的解决方案。
总而言之,你得到了
#!/usr/bin/perl
use strict;
use warnings;
my $s = join "", map { "$_\n" } "a" .. "z";
open my $fh, "<", \$s
or die "could not open in-memory file: $!";
while (my $line = <$fh>) {
if ($. == 1 or not $. % 10) {
print "$. $line";
}
}
请注意,此技巧仅在您使用PerlIO构建perl
时才有效,但这是自Perl 5.8以来的默认设置。如果您的perl
版本未使用Perl IO编译,则需要从CPAN中获取IO::Scalar
。
对于真正疯狂的怪异程度,你可以在内存文件中使用Tie::File
:
#!/usr/bin/perl
use strict;
use warnings;
use Tie::File;
my $s = join "", map { "$_\n" } "a" .. "z";
open my $fh, "<", \$s
or die "could not open in-memory file: $!";
tie my @lines, "Tie::File", $fh
or die "could not tie in-memory file: $!";
my $i = 0;
while (defined $lines[$i]) {
print "$lines[$i]\n";
} continue {
$i += 10;
}
答案 1 :(得分:5)
以下是使用/g
修饰符的正则表达式的方法。
my $count = 0;
my @found;
while($text =~ /\G(.*)\n/g) {
next if $count++ % 10 != 0;
push @found, $1;
}
对于小于100行的小字符串,我比Chas的标量ref文件句柄解决方案快约50%,但在1000行以上,它的速度提高了约20%。
Chas的文件句柄解决方案更安全(如果你写错误的正则表达式,你可以让自己有一个无限循环),更简单,并且不会明显更慢,也不会使用更多的内存。使用它。
答案 2 :(得分:3)
这是一个基准测试,使用我的简单文件句读取与Schwern的正则表达式和Chas。的绑定。
这是在我的Mac Pro上运行的Perl 5.12.2:
Rate Chas. Chas. modified drewk Schwern Chas. sane drewk2 brian
Chas. 70.0/s -- -33% -94% -94% -95% -95% -96%
Chas. modified 104/s 48% -- -91% -91% -92% -93% -94%
drewk 1163/s 1560% 1019% -- -5% -15% -23% -35%
Schwern 1220/s 1641% 1073% 5% -- -11% -20% -32%
Chas. sane 1370/s 1856% 1218% 18% 12% -- -10% -23%
drewk2 1515/s 2064% 1358% 30% 24% 11% -- -15%
brian 1786/s 2450% 1618% 54% 46% 30% 18% --
这是同一台机器上的Perl 5.10.1:
Rate Chas. Chas. modified drewk Schwern Chas. sane drewk2 brian
Chas. 66.9/s -- -35% -94% -95% -95% -96% -96%
Chas. modified 103/s 54% -- -91% -92% -93% -93% -94%
drewk 1111/s 1560% 981% -- -17% -22% -27% -40%
Schwern 1333/s 1892% 1197% 20% -- -7% -12% -28%
Chas. sane 1429/s 2034% 1290% 29% 7% -- -6% -23%
drewk2 1515/s 2164% 1374% 36% 14% 6% -- -18%
brian 1852/s 2667% 1702% 67% 39% 30% 22% --
这些结果并没有让我感到惊讶。 Tie :: File似乎比它应该慢,但我预计它会很慢。它很漂亮,但是我发现Tie :: File在性能方面通常很差,因为它不是一个很难开始的界面。如果您需要随机和重复访问,这很好,但对于单次传递顺序访问,它是错误的工具。查斯。比我认为他在这个例子中真正需要的工作做得多一些。我们知道我们想要的行的索引,所以我们可以只取一个绑定数组。切片比查看每一行的while
循环快约150%。
为了看到极端的结果,我将这些行重复了1000次(因此,文件中大约有1,300,000行):
$scalar = slurp( $file ) x 1000;
这些是Perl 5.12.2上的大文件的结果:
Rate Chas. Chas. modified drewk drewk2 Schwern Chas. sane brian
Chas. 0.695/s -- -32% -91% -94% -94% -95% -96%
Chas. modified 1.02/s 46% -- -86% -91% -92% -93% -94%
drewk 7.38/s 962% 626% -- -34% -39% -47% -59%
drewk2 11.2/s 1512% 1002% 52% -- -7% -19% -38%
Schwern 12.1/s 1635% 1086% 63% 8% -- -13% -33%
Chas. sane 13.9/s 1896% 1264% 88% 24% 15% -- -23%
brian 18.0/s 2495% 1674% 144% 61% 50% 30% --
drewk创建新阵列的解决方案现在显示了他们的扩展问题。因为它们并不比其他解决方案简单,并且它们有这么大的缺点,所以没有理由这样做。
这是我的基准程序。程序中有一点点差异。我的解决方案(和Chas。的第一个解决方案)得到问题文本中提到的第1行,第10行,第20行等等。如破损代码中所述,其他解决方案获得第1行,第11行,第21行等等。但这对于基准测试并不重要。
#!perl
use strict;
use warnings;
use File::Slurp qw(slurp);
use Tie::File;
use Benchmark qw(cmpthese);
use vars qw($scalar);
chomp( my $file = `perldoc -l perlfaq5` );
#$file = '/Users/brian/Desktop/lines';
print "file is $file\n";
$scalar = slurp( $file );
cmpthese( 1000, {
'Chas.' => \&chas,
'Schwern' => \&schwern,
'brian' => \&brian,
'Chas. modified' => \&chas_modified,
'Chas. sane' => \&chas_sane,
'drewk' => \&drewk,
'drewk2' => \&drewk2,
});
sub drewk {
my @arr = split(/\n/, $scalar);
my @found;
for(my $i=0; $i<=$#arr; $i+=10){
# print "drewk[$i] $arr[$i]\n";
push @found, $arr[$i];
}
}
sub drewk2 {
my $i=0;
my @found;
foreach(split(/\n/, $scalar)) {
next if $i++ % 10;
# print "drewk2[$i] $_\n";
push @found, $_;
}
}
sub schwern {
my $count = 0;
my @found;
while($scalar =~ /\G(.*)\n/g) {
next if $count++ % 10 != 0;
# print "schwern[$count] $1\n";
push @found, $1;
}
}
sub chas {
open my $fh, "<", \$scalar;
tie my @lines, "Tie::File", $fh
or die "could not tie in-memory file: $!";
my $i = 0;
my @found = ();
while (defined $lines[$i]) {
# print "chas[$i]: $lines[$i]\n";
push @found, $lines[$i];
} continue {
$i += 10;
}
}
sub chas_modified {
open my $fh, "<", \$scalar;
tie my @lines, "Tie::File", $fh
or die "could not tie in-memory file: $!";
my $highest_multiple = int( $#lines / 10 ) ;
my @found = @lines[ map { $_ * 10 - ($_?1:0) } 0 .. $highest_multiple ];
#print join "\n", @found;
}
sub chas_sane {
open my $fh, "<", \$scalar;
my @found;
while (my $line = <$fh>) {
if ($. == 1 or not $. % 10) {
#print "chas_sane[$.] $line";
push @found, $_;
}
}
}
sub brian {
open my $fh, '<', \$scalar;
my @found = scalar <$fh>;
while( <$fh> ) {
next if $. % 10;
#print "brian[$.] $_";
push @found, $_;
}
}
答案 3 :(得分:-1)
如果Schern的评论是正确的,你的"list of text" means its in a $scalar
解决方法是使用Perl split,那么你可以使用你编写的代码:
sub drewk {
my @arr = split(/\n/, $scalar);
for(my $i=0; $i<=$#arr; $i+=10){
#print $arr[$i],"\n";
}
}
不是使用C风格循环,而是可以编写非常易读的Perl习语来做同样快速的事情:
sub drewk2 {
my $i=0;
my @found;
foreach(split(/\n/, $scalar)) {
next if $i++ % 10;
#print "$_\n";
push @found, $_;
}
}
将这些插入brian的基准,你会得到非常有竞争力的结果:
Rate Chas. Chas. modified Schwern drewk brian drewk2
Chas. 86.1/s -- -37% -95% -95% -96% -96%
Chas. modified 136/s 59% -- -92% -92% -93% -94%
Schwern 1695/s 1869% 1142% -- -3% -14% -22%
drewk 1754/s 1939% 1186% 4% -- -11% -19%
brian 1961/s 2178% 1337% 16% 12% -- -10%
drewk2 2174/s 2426% 1493% 28% 24% 11% --
(this on a iMac 2.93 GHz Intel COre i7 with Perl 5.10)
您没有发布导致发布循环的代码上下文。也许你做过这样的事情:
$scalar="line 1\nline 2\n ... line n";
push @arr, $scalar;
#or
$arr[0]=$scalar;
认为\n
会导致行以不同的数组元素结束?下次发布上下文......
----编辑:
原始帖子指出How can I print 1st, 10th, 20th... lines (not array index) number in a long list of text.
如果通过“长文本列表”表示兆字节和千兆字节,请使用Brian或Chas的文件句柄方法。它光滑,快速,数据不会在内存中重复。如果“长文本列表”是RAM很多的大小,你可以使用split,/ \ n / g等等或者对你和数据有意义的任何东西。
答案 4 :(得分:-1)
my $lineno = 10;
open FILE, "filename.txt";
my @arr = <FILE>;
print $arr[$lineno];