This question continues the previous one about filtering (the variable names are changed from array & search to source & keys).
Suppose there are even more elements and more keys. The program should print only those element of the @source which begin with any of @keys. So, jjjjk will be printed, but jjjkk won't.
Here's the most straightforward way to solve the problem, but it's too slow to be used:
my @source = "aaaaa" .. "kkkkk";
my @keys = "aaaa" .. "jjjj";
.put for @source .grep: /^ @source /;
# produced 4 elements in 60 seconds
# out of 10 ** 4 * 11 = 110_000
# will take ~19 days to finish
Using .Any and .starts-with() makes it ~100x faster:
my @source = "aaaaa" .. "kkkkk";
my @keys = "aaaa" .. "jjjj";
my $keys_any = @keys.any;
.put for @source .grep: *.starts-with($keys_any);
# produced 700 elements in 110 seconds
# will take ~4.5 hours
If we pre-compile the regex, it works much (~15000x) faster:
my @source = "aaaaa" .. "kkkkk";
my @keys = "aaaa" .. "jjjj";
my $keys = "/@keys.join('|')/".EVAL;
.put for @source .grep: /^ <$keys> /;
# produced all the elements in 100 seconds
Nevertheless, it's still too long, so I've decided to take advantage of the fact that all the keys are of the same length. So, I use a Set of @keys to check substrings of the same length of the @source array:
my @source = "aaaaa" .. "kkkkk";
my @keys = "aaaa" .. "jjjj";
my $keys = @keys.Set;
for @source -> $str {
my $substring = $str.substr(0, 4);
if $substring (elem) $keys {
put $str;
next;
}
}
# produced all the elements in 3 seconds
I feel though, that I'm reinventing the wheel and that there should be built-in instruments and methods to do such things?