Perlで配列をソートした後で先頭からn個の要素がほしかった
単純にsortとspliceで書くと2行になって嫌だった
こんな感じです。
use strict;
use warnings;
use Data::Dumper;
my $array_ref = [5,8,3,10,50,4,68,41,11];
my $array_ref2 = [];
@{$array_ref2} = sort { $b <=> $a } @{$array_ref};
splice @{$array_ref2}, 5;
print Data::Dumper::Dumper $array_ref2;
exit;
何がしたいのかはわかるのですが、2行も使うような内容でもないかな、という気持ちでした。
意外とこういう処理ってよくやるような気がするので、もっとすっきりしたかったのです。
いろいろ試したら、こんな風にもかけました。
use strict;
use warnings;
use Data::Dumper;
my $array_ref = [5,8,3,10,50,4,68,41,11];
my $array_ref2 = [];
@{$array_ref2} = ( sort { $b <=> $a } @{$array_ref} )[0..4];
print Data::Dumper::Dumper $array_ref2;
結果は、両方同じで
$VAR1 = [
68,
50,
41,
11,
10
];
なんとなく、すっきりしました。
速度的にはどうなの?
両方を100万回くらい回してみました。
use strict;
use warnings;
use Time::HiRes qw(gettimeofday tv_interval);
my $array_ref = [5,8,3,10,50,4,68,41,11];
my $array_ref2 = [];
my ( $t0, $t1, $et );
$t0 = [gettimeofday];
do{
@{$array_ref2} = sort { $b <=> $a } @{$array_ref};
splice @{$array_ref2}, 5;
} for 0..1000000;
$t1 = [gettimeofday];
$et = tv_interval($t0,$t1);
print "splice: $et\n\n";
$t0 = [gettimeofday];
do{
@{$array_ref2} = ( sort { $b <=> $a } @{$array_ref} )[0..4];
} for 0..1000000;
$t1 = [gettimeofday];
$et = tv_interval($t0,$t1);
print "not splice: $et\n\n";
exit;
結果
splice: 1.048066
not splice: 0.759474
2行使って処理するより早いみたいですね。
ただ、100万回でこの差であればそんなに気にしないでもいいかな、と思ったり。
でも、splice
使ってやるほうだと、代入する配列が巨大であれば、さらに重たくなるような気がします。
配列の要素数を増やしてみた
use strict;
use warnings;
use Time::HiRes qw(gettimeofday tv_interval);
my $array_ref = [1..100]; #面倒なので、単純に1~100の連続した数値を代入しました
my $array_ref2 = [];
my ( $t0, $t1, $et );
$t0 = [gettimeofday];
do{
@{$array_ref2} = sort { $b <=> $a } @{$array_ref};
splice @{$array_ref2}, 5;
} for 0..1000000;
$t1 = [gettimeofday];
$et = tv_interval($t0,$t1);
print "splice: $et\n\n";
$array_ref2 = [];
$t0 = [gettimeofday];
do{
@{$array_ref2} = ( sort { $b <=> $a } @{$array_ref} )[0..4];
} for 0..1000000;
$t1 = [gettimeofday];
$et = tv_interval($t0,$t1);
print "not splice: $et\n\n";
exit;
結果
splice: 6.424075
not splice: 1.541562
予想通り、大幅に差が開きました。
結論
元の配列が大きい場合は、代入する前に要素数を絞れるといいですね、ということですね。