elam has asked for the wisdom of the Perl Monks concerning the following question:

Howdy monks, I must be missing something obvious:

sub change_punch_process { my @numbers; foreach ( $q->param ) { if (/^([0-9]+)/) { foreach (@numbers) { unless ($_ == $1) { push @numbers,$1; } } } } }

I hope this is clear enough.

I want to:
  1. Take my cgi variables and check for numbers at the beginning of the string, if so, store number in $1.
  2. Compare $1 to all the numbers currently residing in @numbers.
  3. If $1 isn't in numbers, put it in.
I'm getting really strange results. Anyone help?

Thank you,
Elam

Edited: ~Thu Nov 21 23:22:19 2002 (GMT) by footpad: Retitled (was "ponder this"), per Consideration

Replies are listed 'Best First'.
Re: pondering array population
by pg (Canon) on Nov 21, 2002 at 20:46 UTC
    It will not work, as you started with an empty @numbers, so it will never go into the inner foreach loop, where your push resides.

    A fix can be:
    sub change_punch_process { my @numbers; @q = ("1a", "2b", "3c", "2k"); foreach ( @q ) { if (/^([0-9]+)/) { my $exists = 0; foreach (@numbers) { $exists = 1 if ($_ == $1) } if (!$exists) {push @numbers, $1;} } } print join(",",@numbers); } change_punch_process;
Re: pondering array population
by LTjake (Prior) on Nov 21, 2002 at 20:50 UTC

    Like pg said, it won't work.

    Perhaps a hash is in order? Here's an example:

    use strict; my %numbers; while (<DATA>) { $numbers{$1}++ if /^(\d+)/; } print "$_\n" foreach keys %numbers; __DATA__ 123askdjha 1ad asldhasd asdklsd123 10 2fer
    Gives:
    1 2 10 123

    Update (fixed code): Alternatively, using an array:

    use strict; my @numbers; while (<DATA>) { /^(\d+)/; push(@numbers, $1) unless grep(/^$1$/, @numbers) || $1 eq ''; } print "$_\n" foreach @numbers; __DATA__ 123askdjha 1ad asldhasd asdklsd123 10 2fer
    Gives:
    123 1 10 2


    --
    Rock is dead. Long live paper and scissors!
Re: pondering array population
by grantm (Parson) on Nov 21, 2002 at 20:50 UTC

    This bit looks fishy:

    foreach (@numbers) { unless ($_ == $1) { push @numbers,$1; } }

    This would push $1 onto @numbers multiple times (once for each existing element that didn't match) except that it never runs at all since @numbers starts out empty. You could use the grep() function to check whether a value occurs in the array, but a better approach would be to use a hash instead and check with exists().

    Also, your subroutine doesn't explicitly return a value.

Re: pondering array population
by DamnDirtyApe (Curate) on Nov 21, 2002 at 20:51 UTC

    Perhaps try it with a hash, like this: (untested)

    sub f { my %numbers ; foreach ( $q->param ) { /^([0-9]+)/ && $numbers{$1}++ ; } return keys %numbers; }

    _______________
    DamnDirtyApe
    Those who know that they are profound strive for clarity. Those who
    would like to seem profound to the crowd strive for obscurity.
                --Friedrich Nietzsche
Re: pondering array population
by elam (Acolyte) on Nov 21, 2002 at 21:25 UTC

    Whoop!

    thanks for the replies, people

    I didn't know there was a grep function in Perl!

    sub change_punch_process { my %transactions; my @numbers; foreach (sort ($q->param)) { if (/^([0-9]+)/) { push (@numbers,$1) unless grep /\b$1\b/, @numbers; } } print "<br><br>@numbers"; }

    As, grantm said, I kept putting in the same numbers over and over.

    IMO, a hash would be overkill. I just need the numbers to append my CGI variables.

    That grep statement should work right?

    At least it is so far.

    Thanks again!

    Elam Ooops! didn't see your reply sensate. Thanks.
      IMO, a hash would be overkill.

      Far less than repeatedly grepping through an array with regular expressions. Either the number exists in the hash or it doesn't. The check takes the same amount of time regardless of the number of elements in the hash (modulo hash bucketing, a subject I really don't want to discuss). With a grep, every new number you add to the array will be checked, every time. The regex is worse, because it has to compile the regex for each parameter and fire up the regex engine for every number checked.

      On the other hand, if you mean "it would be overkill for me to use a hash because I don't understand them and I do understand grep," that makes sense. Except now you do know why to use a hash. :)

Re: pondering array population
by joe++ (Friar) on Nov 21, 2002 at 20:52 UTC
    Hi elam,

    I'm afraid your seond implicitly assigend $_ overwrites the first one. You could try this:

    sub change_punch_process { my %numbers; foreach (my $par = $q->param ) { $numbers{$1}++ if /^([0-9]+)/; { } # now you can get all your numbers with keys %numbers

    --
    Cheers, Joe

Re: pondering array population
by insensate (Hermit) on Nov 21, 2002 at 20:52 UTC
    Try something like this:
    sub change_punch_process { my @numbers; foreach ( $q->param ){ if (/^([0-9]+)/){ $number=$1; push @numbers,$number unless grep{$_==$number}@numbers; } } }