http://www.perlmonks.org?node_id=1025608

dbuckhal has asked for the wisdom of the Perl Monks concerning the following question:

I was using the smart match operator to help generate an array of unique, random numbers. For legacy purposes, I used map in scalar context to do the same thing. Then I saw grep being used in a recent thread in the same manner as my map usage, so I also incorporated that and benchmarked their performances.

Smart match blew the other two away, but what I did find interesting was the resulting difference in the unique arrays generated.

First, to level the playing field for testing, I started with generating a 1_000_000 element array of random numbers to be used as the "pool" that my generator methods would pick against. So, each generator utilized the same pool, rather than another set of random numbers. In the end, it was the generated arrays that were interesting.

Here is a sample of the three unique arrays generated and sorted:

Benchmark: timing 2500 iterations of grepGen, mapGen, smartGen... grepGen: 34 wallclock secs (34.35 usr + 0.00 sys = 34.35 CPU) @ 72 +.78/s (n=2500) mapGen: 14 wallclock secs (14.09 usr + 0.00 sys = 14.09 CPU) @ 17 +7.47/s (n=2500) smartGen: 1 wallclock secs ( 0.95 usr + 0.00 sys = 0.95 CPU) @ 26 +28.81/s (n=2500) Rate grepGen mapGen smartGen grepGen 72.8/s -- -59% -97% mapGen 177/s 144% -- -93% smartGen 2629/s 3512% 1381% -- loop counts - grep: 805000, map: 805000, smart: 495000 array sizes - num: 1000000; grep: 100; map: 100; smart: 100 grep: 1 12 15 18 19 20 21 22 23 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 + 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 + 64 65 66 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 + 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 104 105 106 107 108 +109 110 111 112 113 114 116 117 118 119 map: 1 12 15 18 19 20 21 22 23 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 + 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 + 64 65 66 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 + 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 104 105 106 107 108 +109 110 111 112 113 114 116 117 118 119 smart: 0 1 2 3 5 7 8 9 12 13 15 16 18 19 21 22 23 25 26 27 28 29 30 31 32 33 +34 35 36 37 38 39 42 43 44 45 46 47 48 51 52 53 54 55 56 57 58 59 60 +61 62 63 64 65 66 68 69 70 71 72 73 74 75 76 77 78 79 81 83 84 85 86 +87 89 90 91 92 93 94 95 96 97 98 100 101 102 104 105 106 107 108 109 +110 111 112 113 116 117 118 119

The grep and map arrays are the same, but smart match picked values that the other methods did not! Each method picked from the exact same pool.

This is the curious find that I mentioned in my subject. So, I hope that others can check my code and maybe find the results curious, also.

code

#!/usr/bin/perl use strict; use warnings; use Benchmark qw( timethese cmpthese ); my @doCount = (0); # total loops until unique array generate +d my $range = 120; # numbers range from 0 to $range my $aSize = 1000000; # random pool array size my $uSize = 100; # unique array size my ( @grep, @map, @smart ); my @nums = arrGen(); # generate huge pool of random numbers my $r = timethese( 2500, { grepGen => sub{ @grep = grepGen(); }, mapGen => sub{ @map = mapGen(); }, smartGen => sub{ @smart = smartGen(); }, } ); # show results cmpthese $r; print "loop counts - grep: $doCount[0], map: $doCount[1], smart: $doCo +unt[2]\n"; print "array sizes - num: ", scalar(@nums), # should all == $uSize "; grep: ", scalar(@grep), "; map: ", scalar(@map), "; smart: ", scalar(@smart), "\n"; # show sorted generated arrays to check for a rare duplicate print "grep:\n@{[sortIt(@grep)]}\nmap:\n@{[sortIt(@map)]}\nsmart:\n@{[ +sortIt(@smart)]}\n"; sub arrGen { my @nArray; for ( 1..$aSize ) { my $rInt = int(rand($range)); push @nArray, $rInt; } return @nArray; } sub sortIt { return sort { $a <=> $b } @_; } sub grepGen { my $idx = 0; my @gArray; for ( 1..$uSize ) { $doCount[0]++; my $rInt = $nums[$idx++]; redo if ( @gArray && grep { /$rInt/ } @gArray ); push @gArray, $rInt; } return @gArray; } sub mapGen { my $idx = 0; my @mArray; for ( 1..$uSize ) { $doCount[1]++; my $rInt = $nums[$idx++]; redo if ( @mArray && map { /$rInt/ } @mArray ); push @mArray, $rInt; } return @mArray; } sub smartGen { my $idx = 0; my @sArray; for ( 1..$uSize ) { $doCount[2]++; my $rInt = $nums[$idx++]; redo if ( @sArray && $rInt ~~ @sArray ); push @sArray, $rInt; } return @sArray; }