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

hi guys, newbie question. how do read a flat file sequentially? not randomly. ex. i have this flat file.
1|/images/banners/internal/g.gif|http://www.g.com 2|/images/banners/internal/ad.gif|http://www.ad.com/privicard 3|/images/banners/promos/banner.gif|http://www.blah.com 4|/images/banners/promos/banner_o.gif|http://www.b.com
as you can see i want to create a script that would rotate banner ads. i don't wanna randomly diplay images bec. it sometimes displays 2 images that are the same. i want to be able to display images without diplaying 2 or 3 similar images. here's my code that randomly displays images see if you guys can fix this one.
if(!open DAT, "ads.dat") { print "Error: cannot open data file!\n"; exit 1; } else { @imgdata=<DAT>; close DAT; foreach $c (@imgdata) { ($id,$image,$url)=split(/\|/,$c); if ($type=~/^internal|partner$/) { push (@imgs,$image); push (@urls,$url); push (@des,$desc); } } $index = int(rand($#imgs+1)); $img = $imgs[$index]; $link = $urls[$index]; print qq|Set-Cookie: URL=$link\n|; print qq|Location: $img\n\n|; }
thanks in advance.

Replies are listed 'Best First'.
Re: Reading files sequentially
by chromatic (Archbishop) on Sep 15, 2000 at 06:35 UTC
    Just treat your arrays as queues.
    $img = shift @imgs; $link = shift @urls; # print statements here push @imgs, $img; push @urls, $link;
    While I'm at it, I'd get rid of the temporary array, too:
    while ($c = <DAT>) { ($id,$image,$url)=split(/\|/,$c); if ($type=~/^internal|partner$/) { push (@imgs,$image); push (@urls,$url); push (@des,$desc); } } close DAT;
    I'd also point you to die and $! and maybe even unless in your open statement. But enough for now. :)

    Update: Unless this program is run persistently, it won't work. Hmm -- if this program starts up again for each image, this method won't work, and you'll have to keep track of which image to serve in a file somehow.

    In that case, I'd drop the randomizer and keep a counter file around. merlyn has some examples in his Web Techniques columns. Open the temp file, get the number, check to see if it's a valid index into the array. If not, reset it to zero. Serve the appropriate file, flock it, and write the incremented number to it.

Random and sequential for the price of one!
by gryng (Hermit) on Sep 15, 2000 at 06:51 UTC
    After you choose your index randomly, you could then just increment it by one to determine the next value.

    However since you are doing a website, you may not want the same two ads to always appear next to each other. Therefore, I would do the following:

    1. Read all the images in from the file
    2. Shuffle the array
    3. Pop one image off the end of the array
    4. Repeat (3) until array is empty, then goto (1)

    Check out (ar0n: Algorithm::Numerical::Shuffle) Re: Randomize an array and Answer: How do I shuffle an array? for code on how to shuffle an array.

    Cheers,
    Gryn

      hi grying, thanks for the reply, but is it okay if you could demonstrate you seggestion in my code? thanks, arvin
        sub shuffle { my $array = shift; my $i; for ($i = @$array; --$i; ) { my $j = int rand ($i+1); next if $i == $j; @$array[$i,$j] = @$array[$j,$i]; } } my $counter = 10; # this is the number of images you want open DAT, "ads.dat" or die "Error: cannot open data file!"; my @item; while (my $c=<DAT>) { my ($id,$image,$url)=split(/\|/,$c); push @item, {"image"=>$image,"url"=>$url,"desc"=>$desc}; } close DAT; while ($counter) { my @itemtmp = @item; shuffle(\@itemtmp); while (my $i = pop @itemtmp) { $img = $i->{"image"}; $link = $i->{"url"}; print qq|Set-Cookie: URL=$link\n|; print qq|Location: $img\n\n|; last if --$counter == 0; } }
        Warning, in that I didn't test that code, I only thought about it, and ran it through the syntax checker. Hopefully that is clearer and will help you out!

        Ciao,
        Gryn