I want to filter elements of @array
which begin with elements of @search
:
my @array = "aaaaa" .. "fffff";
my @search = "aaaa" .. "cccc";
.put for @array .grep: /^ @search /;
The problem is it takes 19 seconds. So, I 'precompile' the regex
for grep
, and the whole program looks like this:
my @array = "aaaaa" .. "fffff";
my @search = "aaaa" .. "cccc";
my $search = "/@search.join('|')/".EVAL;
.put for @array .grep: * ~~ /^ <$search> /;
Now it takes 0.444s.
The question: is there a built-in Perl 6 method to do such things? Something like inserting a junction
into a regex
...
my @array = "aaaaa" .. "fffff";
my @search = "aaaa" .. "cccc";
my $join = @search.join('|');
my $rx = rx{ ^ <{$join}> };
@array.grep( * ~~ $rx ).map( *.put )
You need to create the join string separately of it will evaluate the array join for each match. But the basically gives you what you want without using EVAL.
You could try to speed this up by assembling the regexes.
I am not sure how to do this using pure Perl 6 but Regexp::Assemble
is a Perl 5 module that can do this for Perl 5 regexes. You can use Perl 5 modules in Perl 6 code by appending a :from<Perl5>
(without a preceding space) to a use
statement and then accessing its exported symbols (classes, objects, routines, etc.) as if it was a Perl 6 module:
use v6;
use Regexp::Assemble:from<Perl5>;
my @array = "aaaaa" .. "fffff";
my @search = "aaaa" .. "cccc";
my $ra = Regexp::Assemble.new;
$ra.add( @search );
$ra.anchor_string_begin(1);
.put for @array.grep({so($ra.match( $_ ))});
For this kind of search, you can easily use index
say (@array X @search).grep( { defined($^a[0].index($^a[1])) } )
.grep( { $^a[0].index($^a[1]) == 0 } );
This creates a list of Cs, and seeks the second element of the pair within the first; it returns only the list of those that appear in the first position. defined
is needed because it will return Nil
if it does not find it. It's not faster than your alternative above, but it's in the same ballpark, with 0.03 system time and ~ 0.30 seconds