foreach loop

They have: 36 posts

Joined: Oct 2004

I know this is a real pain, but could someone put me straight on the code below.

sub sort_by_num
  {
     return $a <=> $b;
  }

@arr = (500,1,400,5);

foreach (sort sort_by_num(@arr))
   {
      print ("$_\n");
   }
'

From what i can figure out, the return value of sort_by_num should be 1,5,400,500. The problem I have is i have never come across a foreach loop with a subroutine in it. Im guessing that when the foreach loop is started the expression in the parentheses is evaluated first. This would result in the foreach loop effectively saying....foreach (sort 1,5,400,500), but since "sort's" default is to sort by ASCII , this would result in the foreach loop being evaluated as this....foreach (1,400,5,500)..., so the print function should result in this
1
400
5
500
but needless to say, i doesnt.

I THINK MY HEAD MY EXPLODE!!!!!!

As always with me, this is a learning thing,and although grateful im not looking for better code that does the same thing, The answer to this will probably teach me something.

TIA

Abhishek Reddy's picture

He has: 3,348 posts

Joined: Jul 2001

Your conclusion is reasonable -- I can see how the syntax might throw you off. In fact, this is a nuance of the sort function, as it doesn't behave the way Perl's syntax naturally implies. It is similar to C's sort(), if that is familiar to you.

The optional first argument to sort is a subroutine telling it what predicate to use when sorting the sequence. The subroutine isn't evaluated just once in the foreach header -- it's evaluated many times by sort, instead of comparing ASCII values. It only uses the default ASCII sort predicate when you supply no subroutine.

Read it as "sort @arr using my subroutine sort_by_num instead of your default".

To be clearer, you could rewrite the parens like so:
sort (sort_by_num @arr)'

Hope that helps. Smiling

They have: 36 posts

Joined: Oct 2004

Thanks alot.

I think I may need to know Exactly how the sort function works (which list values get compared to which and in what order, and how many times.

If i run this code then "i" ends up being 5,, This I dont understand and probably never will until I know how sort works.

[CODE]
#!c:\perl\bin\perl.exe

sub sort_by_num
{
$i++;
return $a <=> $b;
}

$i=0;
@arr = (500,1,400,5);

foreach (sort sort_by_num(@arr))
{
print "$_\n;"

}

print "i = $i";

[\CODE].

They have: 36 posts

Joined: Oct 2004

I made a miskake and ran this code. I believe it may help to figure out the exact sequence of evevts taking place from the time the sort function starts to be executed.

sub sort_by_num
{
  $i++;
  return $a <=> $b;
}

$i=0;
@arr = (500,1,400,5);

foreach (sort sort_by_num(@arr))
   {
    print "$_\n;";
    
   }

print "i = $i";
'

The output is
1
;5
;400
;500
;i=5

If possible could you explain each stage in the program for me. I know its alot to ask, but ive been driven mad by this problem for 4 days now, and my course tutors are absolutely useless.

I would be very very grateful.

THANX
Stu

Abhishek Reddy's picture

He has: 3,348 posts

Joined: Jul 2001

i measures the number of comparisons made, which can vary depending on the algorithm that the sort function uses. This is a fairly deep subject in computing, so I won't go into much detail here. It's well worth investigating, though. Smiling

Add something like print "$i: $a $b\n"; after your $i++; to see what's going on. It should print:

1: 500 1
2: 400 5
3: 1 5
4: 5 500
5: 500 400
'

Which looks like mergesort.

You may get something different, such as quicksort, depending on your version of Perl (5.6 and earlier use quicksort, 5.7 uses mergesort, 5.8 flips a coin).

They have: 36 posts

Joined: Oct 2004

Cheers Abhishek, Your the Man!!!

Want to join the discussion? Create an account or log in if you already have one. Joining is fast, free and painless! We’ll even whisk you back here when you’ve finished.