在for循环中设置范围计数器的最佳方法是什么?我有一个制表符分隔输入文件,其中前两列很重要.我想找到它们在Pos值范围内出现的分数的最小值和最大值.所以对于示例输入文件:
Pos score 1 5 2 17 9 80 38 22 40 11 7 0 302 19 85 33 12 51 293 1 5 19 61 8 71 15
如果存在,我需要计算每个范围的最小和最大分数.
1-29 (min=?,max=?) 30-59 (min=?,max=?) 60-89 (min=?,max=?)
预期成绩:
1-29 (min=0,max=80) 30-59 (min=11,max=22) 60-89 (min=8,max=33) 290-219 (min=1,max=19)
还有另一个与此相关的线程,但它们只计算具有设定范围的事件.我的尝试是设置for循环:
use List::MoreUtils qw( minmax ); my %inputhash; my %storehash; open (FF,$inputfile) || die "Cannot open file $inputfile"; while(<FF>) { next if $. < 2; #use to trim off first line if there is a header my ($Pos,$score) = split; $inputhash{$Pos} = $score; } for (my $x=1; $x<1600; $x+29) #set to 1600 for now { my $low = $x; my $high = $x+29; foreach my $i ($low...$high) { if (exists $inputhash{$i}) { my $score = $inputhash{$i}; push (@{$storehash{$high}},$score); } } } foreach my $range (sort {$a <=> $b} keys %storehash) { my ($minrange,$maxrange) = minmax @{$storehash{$range}}; print "$range: $minrange,$maxrange\n"; }
解决方法
use strict; use warnings; use List::Util qw(max min); my $step = 30; # group into 30 item ... my @bins; # ... bins <DATA>; # skip line while (<DATA>) { my ($p,$s) = split; push @{$bins[$p / $step]},$s; } for (my $i = 0; $i < @bins; $i++) { next if not $bins[$i]; printf("%d,%d (min %d,max %d)\n",$i * $step,($i + 1) * $step,min(@{$bins[$i]}),max(@{$bins[$i]})); } __DATA__ Pos score 1 5 2 17 9 80 38 22 40 11 7 0 302 19 85 33 12 51 293 1 5 19 61 8 71 15
产量
0,30 (min 0,max 80) 30,60 (min 11,max 22) 60,90 (min 8,max 33) 270,300 (min 1,max 1) 300,330 (min 19,max 19)