http://qs321.pair.com?node_id=69535

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

Fellow monks,

While under the influence of boredom, I wrote the following script:

#!/usr/bin/perl -w use strict; print "What is your insult? "; chomp(my $input = <>); my @matching = qw/disk duck deck/; if ($input eq $matching[0..2]) {die "bastard\n"};

But, when I enter an "insult", the following error occurs:

Argument "" isn't numeric in array element at ./b line 10, <> line 1.

However, when I use a specific scalar reference to an array like so:

#!/usr/bin/perl -w use strict; print "What is your insult? "; chomp(my $input = <>); my @matching = qw/disk duck deck/; if ($input eq $matching[0]) {die "bastard\n"};

I get no such error; but that's hardly a solution.
I didn't think there was a different range operator (than ..) for Strings; but perhaps I'm wrong.
... Or perhaps it's something else?

Thank you for your help - dusk

Replies are listed 'Best First'.
Re: Why does this happen?
by bbfu (Curate) on Apr 04, 2001 at 07:08 UTC

    You're trying to compare a scalar to an array slice (er... actually, it's not even an array slice). You have to supply just one index for the array, you can't supply several to get Perl to implicitly loop on them for you. You have to explicitly loop through the array elements, comparing each one to the input.

    #!/usr/bin/perl -w use strict; print "What is your insult? "; chomp(my $input = <>); my @matching = qw/disk duck deck/; for (@matching) { if ($input eq $_) {die "bastard\n"}; }

    (Updated first paragraph to be more verbose^Wclear.)

    bbfu
    Seasons don't fear The Reaper.
    Nor do the wind, the sun, and the rain.
    We can be like they are.

Re: Why does this happen?
by MeowChow (Vicar) on Apr 04, 2001 at 09:19 UTC
    I'm really surprised nobody has mentioned one of the more idiomatic and concise (though not necessarily efficient) ways to do this, grep:
    die "bastard\n" if grep $input eq $_, @matching;
       MeowChow                                   
                   s aamecha.s a..a\u$&owag.print
Re: Why does this happen?
by premchai21 (Curate) on Apr 04, 2001 at 07:31 UTC
    A slow but possible and fun solution: Quantum::Superpositions. Tested; compiles, runs, and works correctly (I think). Needs Class::Multimethods.
    #!/usr/bin/perl use Quantum::Superpositions; print "What is your insult? "; chomp (my $input = <>); my @matching = qw/disk duck deck/; die if ($input eq any(@matching)); # could also use @matching[0..2]
    :-)
Re: Why does this happen?
by greenFox (Vicar) on Apr 04, 2001 at 07:12 UTC

    Short answer is, use a hash for that :)

    longer answer is that the array doesn't know how to iterate over 0..2 it just wants to return the specified value which it notices isn't numeric, to do what you were trying to do you would have to use a loop... see the short answer :)

    --
    my $chainsaw = 'Perl';

Re: Why does this happen?
by merlyn (Sage) on Apr 04, 2001 at 17:45 UTC
    As for the error message, let's look at:
    $^W = 1; $index = 0..2; # this is your problem - it's initially undef @matching = qw(disk duck deck); $result = $matching[$index]; # and here's your problem, $matching[unde +f]!
    You've done the .. operator in a scalar context, making it the flip-flop range operator, but you've not read any input, so you're not at line 0 yet, so the value is undef (outside the range so far). This value will be true only when $. is between 0 and 2, inclusively.

    -- Randal L. Schwartz, Perl hacker

Re: Why does this happen?
by $code or die (Deacon) on Apr 04, 2001 at 07:42 UTC
    Update: This is bad advice - It doesn't work. See merlyn reply below.

    This works on my system:
    use strict; print "What is your insult? "; chomp(my $input = <>); my @matching = qw/disk duck deck/; if ($input eq $matching[0||1||2]) {die "bastard\n"};


    $ perldoc perldoc
      if ($input eq $matching[0||1||2]) {die "bastard\n"};
      which means exactly the same as:
      if ($input eq $matching[1]) {die "bastard\n"};
      Were you expecting it to mean something different, especially since you said it "works"? In what manner did you mean "works"?

      -- Randal L. Schwartz, Perl hacker

        ahh - I only tested it with $matching[1]. Oops. /me goes red!

        The lesson is... test, test, test - especially if you do something like I did that you've never seen anyone else do (usually for good reason!)

        $ perldoc perldoc
      A reply falls below the community's threshold of quality. You may see it by logging in.
Re: Why does this happen?
by strredwolf (Chaplain) on Apr 04, 2001 at 11:43 UTC
    There's a few problems, which some have touched on. However, what if I typed in a sentence for an insult? It wouldn't match if I used "disk" in a sentence, eh?

    Try this instead:

    #!/usr/bin/perl -w use strict; print "What is your insult? "; chomp(my $input = <>); my @matching = qw/disk duck deck/; foreach $j (@matching) { die "bastard\n" if($input =~ /$j/); }
    Hmmm... can't we precompile these three items, incase they're used often?

    --
    $Stalag99{"URL"}="http://stalag99.keenspace.com";

      You could compile them into a regexp with

      my $re = do { local $"='|'; qr/^(?:@matching)$/ };

      --
      g r i n d e r
Re: Why does this happen?
by Marinegirl (Initiate) on Aug 17, 2005 at 19:35 UTC
    Your monklynesses

    I have a similar problem ....

    I get the warning message "Argument "n" isn't numeric in array element at program.pl line 356."

    My code looks like this:

    foreach $qbase (@query_sequence [$q_start .. $q_end]) { if ($qbase eq ("n"||"N") && $subj_sequence[$qbase] ne ("n"||"N +")) { ++$ncount; } } foreach $sbase (@subj_sequence [$s_start .. $s_end]) { if ($sbase eq ("n"||"N") && $query_sequence[$sbase] ne ("n"||" +N")) { ++$ncount; } }

    My code is intended to mean:
    for each position between a start and end position in an array, if the element at that position is an 'n', and the element at the same position in another array is not an n, ++count. $q_start, $q_end, $s_start, $s_end are numbers. @query_sequence and @subj_sequence are arrays of letters. It works ok apart from the warning! Why does this happen and how do I fix it?

    Many thanks for your help

    Marinegirl x

      Because $qbase is a letter, $query_sequence[$qbase] is not valid. To fix it change to this
      foreach $qbase ($q_start .. $q_end) # qbase is now a number { if ( ($query_sequence[$qbase] =~ /[nN]/) && ($subj_sequence[$qbase] +!~ /[nN]/) ) { ++$ncount; } }
      poj
        I'd keep them separate in case ($#qbase != $#sbase), and since you're not doing anything else with the index, just loop through them all...
        foreach $qbase ( @qbase ) { if ( uc($qbase) eq 'N' ) { ++$ncount; } } foreach $sbase ( @sbase ) { if ( uc($sbase) eq 'N' ) { ++$ncount; } }
        or more concisely...
        do { $ncount++ if /n/i } foreach ( @qbase, @sbase );
        Update: disregard, read the OP wrong

        Update: re-read, and the answer doesn't take into account if subj_sequence is n and query is not...
        foreach my $idx ( 1..$#query_sequence ) { if ( $query_sequence[$idx] =~ /n/i && $subj_sequence[$idx] !~ /n/i ) + { $ncount++; } elsif ( $subj_sequence[$idx] =~ /n/i && $query_sequence[$idx] !~ / +n/i ) { $ncount++; } }
        (Note that it is assumed that $#query_sequence = $#subj_sequence)

        Update: again..
        $ncount = grep { ($qbase[$_] =~ /n/i && $sbase[$_] !~ /n/i) || ($qbase +[$_] !~ /n/i && $sbase[$_] =~ /n/i) } 1..$#qbase;