Forum Moderators: coopster & phranque

Message Too Old, No Replies

for Replacing foreach in PERL

Coding Issue

         

gmyachtsman

2:06 am on Dec 21, 2002 (gmt 0)



I am trying to replace a "foreach statement" with a "for statement in PERL, so that I break up the output into sections with headings in-between.

The code that I want to replace is this:

#foreach $category (@categories) {
# @fields = split (/\¦/, $category);
#
#if (-e "$classdir/$fields[1].shtm") {
#print qq~
#<li><font face="arial" size=2><b><a href="$htmldir/$fields[1].shtm">$fields[0]</a></b><br>
#<font size=1>$fields[2]</font>~;
#}
#
#else {
#print qq~
#<li><font face="arial" size=2><b>$fields[0]</b> <i>(0)</i><br>
#<font size=1>$fields[2]</font>~;
# }
#}

This code would produce an output like this:

Houses for Sale - South Shore (0)
Houses for Sale - North Shore (0)
Houses for Sale - East End (0)
Houses or Apartments for Rent - South Shore (0)
Houses or Apartments for Rent - North Shore (0)
etc.

The code I've tried to replace it with looks like this (essentially replacing $category where it was used with the @categories array):

for(@categories[$i =0]; $i < 10; ++$i) {
@fields = split (/\¦/, @categories[i]);

if (-e "$classdir/$fields[1].shtm") {
print qq~
<li><font face="arial" size=2><b><a href="$htmldir/$fields[1].shtm">$fields[0]</a></b><br>
<font size=1>$fields[2]</font>~;
}

else {
print qq~
<li><font face="arial" size=2><b>$fields[0]</b> <i>(0)</i><br>
<font size=1>$fields[2]</font>~;
}
$fields->reset()

}

If I don't include the $fields->reset() line at the bottom the code prints out like this:

Houses for Sale - South Shore (0)
Houses for Sale - South Shore (0)
Houses for Sale - South Shore (0)
Houses for Sale - South Shore (0)
Houses for Sale - South Shore (0)
Houses for Sale - South Shore (0)
etc (to 10 repetitions)

With the $fields->reset() line it prints once like this:

Houses for Sale - South Shore (0)

How can I get this to work? As far as I could see it should work fine without reset -- but it obviously works neither way.

(Note: Later I will want to use several separate for statements, replacing the number 10 that i goes up to with a different variable for each section of the page.)

For anyone interested this is a hack of a free classifieds program.

gmyachtsman

5:07 am on Dec 21, 2002 (gmt 0)



I am not sure what I was missing, but in any case I got it to work using this code instead (I gave up trying to use a for statement):

@realestate = @categories[0 .. 10];
@jobs = @categories[11 .. 18];

foreach $category (@realestate) {
@fields = split (/\¦/, $category);

if (-e "$classdir/$fields[1].shtm") {
print qq~
<li><font face="arial" size=2><b><a href="$htmldir/$fields[1].shtm">$fields[0]</a></b><br>
<font size=1>$fields[2]</font>~;
}

else {
print qq~
<li><font face="arial" size=2><b>$fields[0]</b> <i>(0)</i><br>
<font size=1>$fields[2]</font>~;
}
}
print qq~
</ul>
<P>

<ul>~;

foreach $category (@jobs) {
@fields = split (/\¦/, $category);

if (-e "$classdir/$fields[1].shtm") {
print qq~
<li><font face="arial" size=2><b><a href="$htmldir/$fields[1].shtm">$fields[0]</a></b><br>
<font size=1>$fields[2]</font>~;
}

else {
print qq~
<li><font face="arial" size=2><b>$fields[0]</b> <i>(0)</i><br>
<font size=1>$fields[2]</font>~;
}
}

print qq~
</ul>
<P>

Though it was in the code, in the previous example I had left off the

print qq~
</ul>
<P>

that probably didn't make much difference to anyone trying to figure it out.

The key here was this:

# You can grow arrays dynamically; the subscript of the highest element in an array @array is represented
# by the variable $#array, and the index of the base element of an array is set by the global variable $[
# (which is normally 0 but can be 1, or can be reset to anything you like).
# $array[n] is the nth element of @array. You can refer to a range of variables in an array; for example:
# @array2 = @array1[1 .. 4]
# assigns elements 1 through 4 of @array1 to @array2.
# And:
# @array2 = (@array1[($#array1-4) .. $#array1]);
# assigns the last five elements of @array1 to @array2.

I found that here: [antipope.org...]

seindal

11:05 am on Dec 21, 2002 (gmt 0)

10+ Year Member



This

for(@categories[$i =0]; $i < 10; ++$i) {

should be


for($i = 0; $i < 10; $i++) {
do something with $categories[$i];
}

gmyachtsman

2:48 pm on Dec 21, 2002 (gmt 0)



Thanks,

I just tried something like you suggested:

for($i =0; $i < 10; ++$i) {
@fields = split (/\¦/, $categories[i]);

etc (taking out the reset() function)

The output was the same as before:

Houses for Sale - South Shore (0)
Houses for Sale - South Shore (0)
Houses for Sale - South Shore (0)
(10 times)

It won't really matter to me if I can't get the for loop to work here -- since I found an alternate solution -- though I do have some curiosity about why it isn't working.

gmyachtsman

2:54 pm on Dec 21, 2002 (gmt 0)



Oh -- I see what was wrong -- I didn't use the [$i], using the $ sign before the i, it works --- thanks.

gmyachtsman

3:06 pm on Dec 21, 2002 (gmt 0)



Strangely enough, I went back to see if the [$i] was the only problem in my original:

for(@categories[$i =0]; $i < 10; ++$i) {
@fields = split (/\¦/, @categories[i]);

Fixing the [$i], I got otput like this:
Houses for Sale - South Shore¦sale_ss¦ (0)
Houses for Sale - North Shore¦sale_ns¦ (0)
Houses for Sale - East End¦sale_ee¦ (0)
Houses or Apartments for Rent - South Shore¦rent_ss¦ (0)
Houses or Apartments for Rent - North Shore¦rent_ns¦ (0)
(10 lines)

This output too may fields. And it even does the same extra output when I change the second @categories[$i] to $catergories[$i] (or both the first and the second too)

seindal

5:42 pm on Dec 21, 2002 (gmt 0)

10+ Year Member



The for is still wrong, but works due to a peculiarity

You have

for(@categories[$i =0]; $i < 10; ++$i) {

@categories[$i =0] is evaluated in steps. First $i=0 is evaluated. It sets $i to 0, which is also the value of the assigment. Assignments are expressions, not statements, in perl. Then you have @categories[0], which is an array slice; another peculiarity of perl. An array slice is a subset of an array, in this case just one element, so the result is a list of one element, or ($categories[0]).

So your loop works, because $i=0 afterwards, and the rest is just discarded.

Hence,

for($i =0; $i < 10; ++$i) {

is just as good and faster.

René.

amoore

6:31 pm on Dec 21, 2002 (gmt 0)

10+ Year Member



'for' and 'foreach' are synonyms in perl.
Also, you can write C code in perl, or for a more perlish way, you can do something like

foreach my $i (1..10) {

or even


foreach (1..10) {

(and then use $_ as your iterator)

instead of


for($i =0; $i < 10; ++$i) {

Doesn't really change much, but it looks more like perl style.

gmyachtsman

7:41 pm on Dec 21, 2002 (gmt 0)



Thanks, seindal and amoore.

siendal, actually the method I was trying to use did not work right because it printed out more fields than asked for (it even got worse later in the classifieds list where I had a fourth field).

amoore, I see ... and "my" makes it a local variable. Thanks.