Beefy Boxes and Bandwidth Generously Provided by pair Networks
Keep It Simple, Stupid
 
PerlMonks  

Re: Simple Math Puzzle...

by hv (Prior)
on May 10, 2003 at 12:43 UTC ( [id://257121]=note: print w/replies, xml ) Need Help??


in reply to Simple Math Puzzle...

One initial note: "10234" would be a better starting point than "12345".

For the problem sub check_duplicates(), if you're going to write it that way you need to allow for the fact that you'll get 5 mandatory matches, when you compare digit-1 to digit-1 etc: you can allow for that by subtracting 5 from $flag.

Another approach is to use indices to iterate over the arrays so that you can avoid comparing a digit against itself:

for my $i (0 .. $#digits) { for my $j (0 .. $#digits) { next if $i == $j; ++$flag if $digit[$i] == $digit[$j]; } }

Another way to avoid it, since an equality check is symmetrical, is to iterate the inner loop only over the digits following the current outer digit:

for my $i (0 .. $#digits) { for my $j ($i + 1 .. $#digits) { ++$flag if $digits[$i] == $digits[$j]; } }

But I'd rather use a simple regexp:

sub check_duplicates { my $candidate = shift; ++$flag if $candidate =~ /(.).*\1/; }

For check_prime(), note that a character class (/[2357]/) is more efficient than an alternation (/2|3|5|7/), but for counting the number of occurrences of a class of characters tr/// is faster still:

sub check_prime { my $candidate = shift; ++$flag if 2 != $candidate =~ tr/2357//; }

As a general efficiency rule, duplicated effort is a red flag: rather than let each check subroutine split the candidate to an array, you could do it once in the main loop and pass a reference to the resulting array as a second argument to the relevant check subroutines.

Note also that you can gain time by ordering the check subroutines so that the ones most likely to fail or quickest to check appear earlier (at least if you also follow others' advice and short-circuit on the first failure) - in this respect, I'd check for duplicates first, but I'd also be inclined to avoid checking all of (for example) 44000 .. 44999 by checking for where the first duplicate occurs:

for (my $candidate = 10234; $candidate <= 98765; ++$candidate) { # we want to jump eg from 10992 to 11000 # note not 'next': we've already incremented if the s/// succeeds redo if $candidate =~ s{ ^ (.*? (.) .*? \2) (.*) }{ ($1 + 1) . ("0" x length($3)) }ex; ... }

On another topic, you've done a good job of writing self-documenting code here, but I should mention that while I agree with other respondents about removing the use of $flag, I'd otherwise suggest renaming it - since it will have a true value if the candidate is not acceptable, I'd call it something like $bad or $fail and then finish the main loop with:

print "$candidate\n" unless $bad;

Hugo

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: note [id://257121]
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others lurking in the Monastery: (2)
As of 2024-04-24 16:24 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found