use warnings; use strict; use Benchmark "cmpthese"; use List::Util "shuffle"; use constant DO_CHECK => 0; use if DO_CHECK, "Data::Compare", qw/Compare/; my $bnd = 50; my @in = shuffle (-$bnd .. $bnd); my $exp = [ 0 .. $bnd, -$bnd .. -1 ]; cmpthese (-2, { sortfirst => sub { my @list = @in; @list = sort { $a <=> $b } @list; @list = ((grep { $_ >= 0 } @list), (grep { $_ < 0 } @list)); DO_CHECK and (Compare (\@list, $exp) or die "@list"); }, grepfirst => sub { my @list = @in; my @pos = grep { $_ >= 0 } @list; my @neg = grep { $_ < 0 } @list; @list = ((sort { $a <=> $b } @pos), (sort { $a <=> $b } @neg)); DO_CHECK and (Compare (\@list, $exp) or die "@list"); }, packunpck => sub { my @list = map { unpack "l>", $_ } sort map { pack "l>", $_ } @in; DO_CHECK and (Compare (\@list, $exp) or die "@list"); }, pryrt => sub { sub sgn { $_[0] < 0 ? -1 : 1 } my @list = sort { (sgn ($b) <=> sgn ($a)) || ($a <=> $b) } @in; DO_CHECK and (Compare (\@list, $exp) or die "@list"); }, choroba => sub { my @list = sort { ((-1, 0, 1)[$a <=> 0] <=> (-1, 0, 1)[$b <=> 0]) || ($a <=> $b) } @in; DO_CHECK and (Compare (\@list, $exp) or die "@list"); }, choroba0 => sub { # from CB my @list = sort { (($b + .5 <=> 0) <=> ($a + .5 <=> 0)) || ($a <=> $b) } @in; DO_CHECK and (Compare (\@list, $exp) or die "@list"); }, choroba2 => sub { my @list = sort { ((($a <=> 0) & 3) <=> (($b <=> 0) & 3)) || ($a <=> $b) } @in; DO_CHECK and (Compare (\@list, $exp) or die "@list"); }, eily => sub { my @list = sort { ~$b <=> ~$a } @in; DO_CHECK and (Compare (\@list, $exp) or die "@list"); }, vr => sub { # https://www.perlmonks.org/?node_id=1229415 my @list = unpack "i*", pack "I*", sort { $a <=> $b } unpack "I*", pack "i*", @in; DO_CHECK and (Compare (\@list, $exp) or die "@list"); }, Discipulus => sub { # https://www.perlmonks.org/?node_id=1229419 my @list = sort {$a<=>$b} @in; push @list, shift @list until $list[0] >= 0; DO_CHECK and (Compare (\@list, $exp) or die "@list"); }, haukex3 => sub { # based on sortfirst above my @list = sort { $a <=> $b } @in; my $i; for (0 .. $#list) { if ($list[$_] >= 0) { $i = $_; last; }} # with this module is ~5% faster: # use List::MoreUtils::XS "firstidx"; # my $i = firstidx { $_ >= 0 } @list; @list = (@list[$i .. $#list], @list[0 .. $i-1]); DO_CHECK and (Compare (\@list, $exp) or die "@list"); }, johngg => sub { # https://www.perlmonks.org/?node_id=1229410 my @list = map { unpack q{xl>}, $_ } sort map { my $neg = $_ < 0 ? 1 : 0; pack q{Cl>}, $neg, $_; } @in; DO_CHECK and (Compare (\@list, $exp) or die "@list"); }, Corion => sub { # based on Corion's idea in the CB my @list = sort { $a >= 0 && $b < 0 ? -1 : ($a < 0 && $b >= 0 ? 1 : $a <=> $b) } @in; DO_CHECK and (Compare (\@list, $exp) or die "@list"); }, swl2 => sub { my @list = sort {$a<=>$b} @in; my $i = 0; $i++ while ($list[$i] < 0); push @list, splice @list, 0, $i; DO_CHECK and (Compare (\@list, $exp) or die "@list"); }, tybalt89 => sub { my $high = my @list = sort { $a <=> $b } @in; my $mid = my $low = 0; $list[$mid = $low + $high >> 1] < 0 ? ($low = $mid + 1) : ($high = $mid) while $low < $high; push @list, splice @list, 0, $low; DO_CHECK and (Compare (\@list, $exp) or die "@list"); }, GrepPos => sub { my @list = @in; my $pos = grep { $_ >= 0 } @list; @list[$pos .. $#list, 0 .. $pos - 1] = sort { $a <=> $b } @list; DO_CHECK and (Compare (\@list, $exp) or die "@list"); }, # hdb => sub { # my @list = sort { $a * $b > 0 ? $a <=> $b : $b <=> $a } @in; # DO_CHECK and (Compare (\@list, $exp) or die "@list"); # }, });