Filtering an array with many keys of the same length in Perl 6

This question continues the previous one about filtering (variable names change from arrayand searchto sourceand keys).

Suppose there are even more elements and more keys. The program should print only those elements @sourcethat begin with any of @keys. So it jjjjkwill be printed, but jjjkkit will not.

Here's the easiest way to solve the problem, but it is too slow to use:

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

Use .Anyand .starts-with()makes it ~ 100 times 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 precompile the regular expression, 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

, , , . , Set of @keys @source:

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

, ?

+4
2
+3

, Sets , , .substr Q.

my @source = "aaaaa" .. "kkkkk";
my @keys = "aaaa" .. "jjjj";
my $keys = @keys.Set;

for @source -> $str {
  $str ~~ m/ ^ ( . ** 4 ) <?{ ~$0 (elem) $keys }> /;
  put $str if so $/;
}

# produced all the elements in 11 seconds
+1

Source: https://habr.com/ru/post/1689374/


All Articles