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"); # }, }); #### Linux 4.20.6-1-default [openSUSE Tumbleweed 20190202] HP ZBook 15G3 Core(TM) i7-6820HQ CPU @ 2.70GHz/3480(8 cores) x86_64 15958 Mb Rate pryrt choroba0 choroba choroba2 johngg Corion packunpck eily grepfirst sortfirst haukex3 GrepPos vr swl2 tybalt89 Discipulus pryrt 2427/s -- -30% -41% -53% -61% -62% -68% -71% -81% -84% -87% -89% -90% -90% -92% -93% choroba0 3486/s 44% -- -16% -32% -44% -46% -53% -59% -73% -77% -82% -84% -86% -86% -88% -89% choroba 4129/s 70% 18% -- -20% -34% -36% -45% -51% -68% -73% -78% -82% -83% -84% -86% -87% choroba2 5132/s 111% 47% 24% -- -18% -20% -31% -39% -60% -66% -73% -77% -79% -80% -82% -84% johngg 6280/s 159% 80% 52% 22% -- -3% -16% -25% -51% -59% -67% -72% -74% -75% -78% -81% Corion 6455/s 166% 85% 56% 26% 3% -- -14% -23% -49% -58% -66% -71% -73% -74% -78% -80% packunpck 7469/s 208% 114% 81% 46% 19% 16% -- -11% -41% -51% -61% -67% -69% -70% -74% -77% eily 8413/s 247% 141% 104% 64% 34% 30% 13% -- -34% -45% -56% -62% -65% -67% -71% -75% grepfirst 12739/s 425% 265% 209% 148% 103% 97% 71% 51% -- -16% -33% -43% -47% -49% -56% -61% sortfirst 15244/s 528% 337% 269% 197% 143% 136% 104% 81% 20% -- -20% -32% -37% -39% -47% -54% haukex3 19002/s 683% 445% 360% 270% 203% 194% 154% 126% 49% 25% -- -15% -21% -24% -34% -42% GrepPos 22333/s 820% 541% 441% 335% 256% 246% 199% 165% 75% 46% 18% -- -8% -11% -23% -32% vr 24206/s 897% 594% 486% 372% 285% 275% 224% 188% 90% 59% 27% 8% -- -4% -16% -27% swl2 25121/s 935% 621% 508% 390% 300% 289% 236% 199% 97% 65% 32% 12% 4% -- -13% -24% tybalt89 28845/s 1088% 727% 599% 462% 359% 347% 286% 243% 126% 89% 52% 29% 19% 15% -- -13% Discipulus 33027/s 1261% 847% 700% 544% 426% 412% 342% 293% 159% 117% 74% 48% 36% 31% 14% -- #### Linux 4.4.165-81-default [openSUSE Leap 42.3] HP Z420/1589 Xeon(R) CPU E5-1650 0 @ 3.20GHz/3533(12 cores) x86_64 15972 Mb Rate pryrt choroba0 choroba Corion choroba2 johngg packunpck eily grepfirst sortfirst haukex3 GrepPos vr swl2 tybalt89 Discipulus pryrt 6019/s -- -40% -40% -54% -56% -62% -72% -77% -84% -87% -88% -90% -90% -92% -92% -93% choroba0 9954/s 65% -- -1% -23% -28% -37% -53% -61% -74% -79% -81% -83% -84% -86% -87% -89% choroba 10046/s 67% 1% -- -23% -27% -36% -53% -61% -73% -79% -81% -83% -83% -86% -87% -88% Corion 12970/s 115% 30% 29% -- -6% -18% -39% -50% -66% -73% -75% -78% -79% -82% -84% -85% choroba2 13770/s 129% 38% 37% 6% -- -13% -35% -46% -64% -71% -73% -77% -77% -81% -83% -84% johngg 15761/s 162% 58% 57% 22% 14% -- -26% -39% -58% -67% -70% -73% -74% -78% -80% -82% packunpck 21299/s 254% 114% 112% 64% 55% 35% -- -17% -44% -55% -59% -64% -65% -71% -73% -75% eily 25713/s 327% 158% 156% 98% 87% 63% 21% -- -32% -46% -50% -56% -57% -65% -68% -70% grepfirst 37834/s 529% 280% 277% 192% 175% 140% 78% 47% -- -20% -27% -36% -37% -48% -52% -56% sortfirst 47348/s 687% 376% 371% 265% 244% 200% 122% 84% 25% -- -8% -20% -22% -35% -40% -45% haukex3 51687/s 759% 419% 414% 299% 275% 228% 143% 101% 37% 9% -- -13% -14% -29% -35% -40% GrepPos 59076/s 882% 494% 488% 355% 329% 275% 177% 130% 56% 25% 14% -- -2% -19% -25% -32% vr 60424/s 904% 507% 501% 366% 339% 283% 184% 135% 60% 28% 17% 2% -- -17% -24% -30% swl2 73079/s 1114% 634% 627% 463% 431% 364% 243% 184% 93% 54% 41% 24% 21% -- -8% -16% tybalt89 79276/s 1217% 696% 689% 511% 476% 403% 272% 208% 110% 67% 53% 34% 31% 8% -- -9% Discipulus 86809/s 1342% 772% 764% 569% 530% 451% 308% 238% 129% 83% 68% 47% 44% 19% 10% --