in reply to Re^2: Why is "any" slow in this case?
in thread Why is "any" slow in this case?

Three remarks

Happy testing!

Cheers Rolf
(addicted to the Perl Programming Language :)
see Wikisyntax for the Monastery

°) TIMTOWTDI

Replies are listed 'Best First'.
Re^4: Why is "any" slow in this case?
by Anonymous Monk on Jul 28, 2025 at 14:04 UTC
    hash => sub { while ( $data =~ /^(\d+) (\d+)/mg ) { next if exists $hash{$1} or exists $hash{$2}; } return 1; }, ahead => sub { while ( $data =~ /^(?!(?:0|15|16|31)\D)(\d+)\N{SPACE} (?!(?:0|15|16|31)\D)(\d+)/mgx ) { } return 1; }, Rate hash ahead hash 1742/s -- -31% ahead 2541/s 46% --

    Wow, thanks. I'll refactor with this, then. As to (1), simply generating a list of few hundred captures is slower, even without working it in pairs later. Sorry about (3), I didn't mean to reproach anyone.

      > Wow, thanks. I'll refactor with this, then.

      please test thoroughly, I just hacked the code into my mobile as an example ... be also careful about the numbering of the captures or use an (?:...) for non-capture in the negative list.

      > simply generating a list of few hundred captures is slower,

      I can't follow, since you are using the /g modifier, each iteration will only capture 2 groups and then continue where it left of.

      hence my ( $c, $r ) = ( $data =~ /^(\d+) (\d+)/mg ) should nicely do.

      (Haven't tested the performance, but every statement normally counts)

      > I'll refactor

      You initially said that performance wasn't an issue and you were just curious.

      I'd rather recommend to go for the clearest code, not for the fastest. Because in the long run maintenance costs you the most.

      Cheers Rolf
      (addicted to the Perl Programming Language :)
      see Wikisyntax for the Monastery

        Re a few hundred, the data/code was simplified for this question, I'm guessing the real code does have hundreds.
        I can't follow, since you are using the /g modifier, each iteration will only capture 2 groups and then continue where it left of

        /g in list context consumes till the end of string; iterating with "while" is infinite loop (all but two captures are thrown away each time), or did I misunderstood completely? OK, nevermind

        > please test thoroughly, I just hacked the code into my mobile as an example ...

        as expected the first approach was buggy.

        This approach seems to pass the tests (using 1 for 0 to test more edge cases)

        Hint: Anchoring is tricky when dealing with variable length strings and look-aheads.

        use v5.14; use warnings; say "INPUT: ",my $str = join " ", 0 ..34; my %DONT; @DONT{1, 15, 16, 31}=(); my $stop=15; my $donts = join "|", keys %DONT; say my $dont_re = "(?!(?:$donts)\\b)"; while ( $str =~ m/\b$dont_re(\d+) \b$dont_re(\d+)/g ) { say "$1 $2"; die unless $stop--; exists $DONT{$_} and die "$_ forbidden" for $1,$2; }

        INPUT: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 2 +4 25 26 27 28 29 30 31 32 33 34 (?!(?:31|1|15|16)\b) 2 3 # <-- no 0,1 4 5 6 7 8 9 10 11 12 13 # <-- no 14,15,16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 # <-- no 31 32 33 # <-- no 34

        Cheers Rolf
        (addicted to the Perl Programming Language :)
        see Wikisyntax for the Monastery

        UPDATE

        had to improve the rexex again... :/

        Probably a negative-look-behind is easier and faster.