Beefy Boxes and Bandwidth Generously Provided by pair Networks
Just another Perl shrine
 
PerlMonks  

Re^2: Fastest way to "pick without replacement"

by choroba (Cardinal)
on Nov 21, 2020 at 00:31 UTC ( [id://11123952]=note: print w/replies, xml ) Need Help??


in reply to Re: Fastest way to "pick without replacement"
in thread Fastest way to "pick without replacement"

Have you tried setting TEST to 1? The implementation of grep is wrong, it overwrites the result in each iteration of the for loop. Also, removing just half of the indices shows most of the code needs to be fixed.
#!/usr/bin/perl use warnings; use strict; use Benchmark qw{ cmpthese }; use List::Util qw{ shuffle }; my @numbers = 0 .. 20; my @indices = shuffle(grep $_ % 2, 0 .. $#numbers); my @expect = (0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20); use constant TEST => 1; cmpthese(-2, { splice => sub { my @output = @numbers; for my $index (sort { $b <=> $a } @indices){ splice @output, $index, 1; } join("\0", @output) eq join("\0", @expect) or die "@output\n@e +xpect" if TEST; }, grep => sub { my @output = @numbers[ grep { my $number = $_; ! grep $number == $_, @indices } 0 .. $#numbers ]; join("\0", @output) eq join("\0", @expect) or die "@output\n@e +xpect" if TEST; }, hash => sub { my %ha; @ha{0..$#numbers} = (); for my $index (@indices){ delete $ha{$index}; } my @output = @numbers[ sort { $a <=> $b } keys %ha ]; join("\0", @output) eq join("\0", @expect) or die "@output\n@e +xpect" if TEST; }, hash_slice => sub { my %indices; @indices{0 .. $#numbers} = (); delete @indices{@indices}; my @output = @numbers[sort { $a <=> $b } keys %indices]; join("\0", @output) eq join("\0", @expect) or die "@output\n@e +xpect" if TEST; } });
The order hasn't changed, but the ratios have (result with TEST set back to 0):
Rate grep hash hash_slice splice grep 65163/s -- -42% -45% -89% hash 112778/s 73% -- -5% -81% hash_slice 118725/s 82% 5% -- -80% splice 580859/s 791% 415% 389% --
(swl's solution included slightly improved.)

Update: But using a nested loop (grep in grep) is inefficient and is probably not how I would have changed the original code removing a single element. I'd rather use something like

grep => sub { my %indices; @indices{@indices} = (); my @output = @numbers[ grep ! exists $indices{$_}, 0 .. $#numbers ]; join("\0", @output) eq join("\0", @expect) or die "@output\n@e +xpect" if TEST; },

which leads to (TEST = 0)

Rate hash hash_slice grep splice hash 113323/s -- -6% -41% -80% hash_slice 120876/s 7% -- -37% -79% grep 190934/s 68% 58% -- -66% splice 568237/s 401% 370% 198% --

map{substr$_->[0],$_->[1]||0,1}[\*||{},3],[[]],[ref qr-1,-,-1],[{}],[sub{}^*ARGV,3]

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: note [id://11123952]
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others browsing the Monastery: (4)
As of 2024-04-24 04:53 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found