0

My foreach loop is not working as I wish it to. I want it to loop through the array and find when one element is present and when the element is not present. However, I get all of them saying Not an apple.

@fruit = ('apple','orange','pear');

foreach(@fruit){
     if(@fruit != 'apple'){
          print "Not an apple\n";
     }
     else{
          print "Is an apple\n";
     }
}
Sinan Ünür
  • 116,958
  • 15
  • 196
  • 339
Question_Guy
  • 323
  • 2
  • 3
  • 17

3 Answers3

7

Strings are compared using eq (equal) and ne (not equal). $_ is implicit foreach variable and it should be used like,

if ($_ ne 'apple')

If you want to use explicit loop variable:

foreach my $v (@fruit) {

     if($v ne 'apple'){
          print "Not an apple\n";
     }
     else{
          print "Is an apple\n";
     }
}

Now, why do you get all "Not an apple\n" printed for all elements of @fruit? First, the != results in the left-hand side being evaluated in scalar context which gives the number of elements of @fruit, i.e. 3. On the other hand, 'apple', not being numeric, evaluates to 0 in this numeric comparison for equality. Therefore, the if condition, for each element of the array reduces to:

if (3 != 0) {

and, of course, that holds for every element of the array, regardless of what that array element is.

Sinan Ünür
  • 116,958
  • 15
  • 196
  • 339
mpapec
  • 50,217
  • 8
  • 67
  • 127
2

Using the modules strict and warnings will help you avoid these mistakes. http://www.perlmonks.org/?node_id=111088

Neil H Watson
  • 1,002
  • 1
  • 14
  • 31
2

Let's use a bit more modern way of writing Perl:

use strict;
use warnings;
use feature qw(say);

my @fruits = qw( apple orange pear );
for my $fruit ( @fruits ) {
   if ( $fruit ne 'apple' ) {
      say "$fruit is not an apple";
   }
   else {
      say "This is an apple.";
   }
}

You made several mistakes in your code, and if you had use warnings; in your code, Perl would have told you about them. This is why use warnings should always be included. The use strict forces you to use stricter syntax which means that you can't use barewords (you must quote strings and make sure functions are property declared). And, you have to declare your variables (usually with my).

You had:

foreach (@fruit) {

which means that each fruit would be in the $_ variable, but instead, you were using

if ( @fruit != ... )

In your if statements. That is, you're comparing the entire @fruit array to the value. Also, the != is for numeric comparisons only. You want ne for string comparisons. The use warnings would have caught both of these errors.

Your if statements should have looked like:

if ( $_ ne '...' ) {

However, I don't usually recommend to use $_ for a variety of reasons. It's original purpose was to make the code easier to read, but it usually fails at that. Instead, I usually will use an explicit variable name:

for my $fruit ( @fruits ) {

instead of

foreach (@fruit);

Also note that I use plurals when naming arrays and hashes (since they're usually groups of objects anyway), this way, I don't end up with @fruit, $fruit, and %fruit which can be confusing (although legal). You could add a suffix (i.e. @fruit_list) to help clarify an array from the individual variable too.

I also like using say instead of print because say automatically adds that \n to the end of my printed output. I get the say command when I add in the pragma feature qw(say); to my program.

I also like using qw(...) to define one word lists. It's cleaner and easier to read than using quotes and commas. Note I do not add commas between my fruit names.

David W.
  • 105,218
  • 39
  • 216
  • 337