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

I have a hash full of information and I want two things to occur. I want only six hash elements printed per page, if there are more than six, a link to a url_param for a new page will be created to link to the next set of six (and so on, and so forth). So basically, I want it setup so only six hash parts will be displayed on a single page and have the script automatically create a page link to all other pages (if there are more than six).

Let's say I have 38 hash keys. I will have keys 1-6 on page 1, 7-12 on page 2 ........ 37-88 on page 7. And on the bottom of the displayed information will be a link for each set of six images. All I need to know is how to setup the link for each six and if there are extras (like we had 38, those last 2 keys would be on their own page) those get listed too.

Thank you.

Replies are listed 'Best First'.
Re: dividing a hash by sets of $num
by BUU (Prior) on Mar 14, 2004 at 08:12 UTC
    Step 1: Find some way to get a list of hash keys that has a stable order. Hashes are unordered so theres no way to know where any 6 items happen to lie in correlation to each other. My first thought would be just sorting the keys but other methods will work.

    Step 2: Create a param that stores what page you're on and pass it in your "next" link. Example, foobar.com?page=3. Page is your "counter variable".

    Step 3: Multiply your counter variable by the number of items you want to display per page as an indice in to your array.

    Step 4: Use your indices to extract a list of keys from your array of keys, then use this list to extract a list of elements from your hash.

    Sample code:
    use CGI; my $c = CGI->new(); my %hash = qw/data and stuff/; #however you fill the hash #Step 1 my @keys = sort keys %hash; # this should maintain the same order, ass +uming hash doesn't change #Step 2 my $counter = $c->param('page'); #step 3 my $begin = $counter * $items_per_page; my $end = $begin + $items_per_page; #step 4 print @hash{ @keys[ $begin..$end ] }; #deep voodoo
      I thank you for your wisdom but I hope you don't mind me asking you a question or two about your example.

      By param do you mean url_param for the page? I thought if it was given by the browser, it had to be url_param. I've never really tried it the way you do everything else..perhaps I should.

      We have 13 keys.. --page 2-- $begin would be (2) * 6 = 12 $end would be 12 + 6 = 18. Page two would display items 12-18 which would actually be 7 numbersm +right?
        1) By param I meant a key=value paramater passed to your script via CGI (I'm assuming this is cgi). These come in two forms, a "post" type, and your script reads those via STDIN and "get" types, which come after the question mark in the url. CGI.pm decodes both of these and gives you the value(s) with the method "param". Note that if there are any "posted" paramaters, CGI.pm will only return those when you call param, it will ignore any params in the "get" request.
        #incoming url = script.cgi?foo=bar&baz=qux my $c = CGI->new(); print $c->param('foo'); #prints bar print $c->param('baz'); #prints qux
        2) Uh, I guess. Thats an implementation issue, doesn't really matter.
Re: dividing a hash by sets of $num (aka Paging)
by tachyon (Chancellor) on Mar 14, 2004 at 13:46 UTC

    You can use a pager routine like this. You need to have your data in an array to fix the order as suggested. Show say 1-6 represents 0-5 in our array so these are the values we pass back to script in start and end.

    my $pages = 25; my $curr_page = 13; my $page_size = 6; my ( $links, $curr_range) = pager("/cgi-bin/script.pl", $pages, $curr_ +page, $page_size); print "Current page array[$curr_page] display range $curr_range\n\n", +$links; sub pager { my ( $link, $total, $curr_page, $page_size ) = @_; $link .= $link =~/\?/ ? "&" : '?'; $curr_page ||= 0; $page_size ||= 6; my @links; my $current_range = 'Unkown'; for ( my $start = 0; $start < $total; $start += $page_size ) { my $end = ($start+$page_size)>$total ? $total : $start+$page_s +ize; my $range = $start+1 == $end ? $start+1 : sprintf "%d-%d", $st +art+1, $end; $end -=1; # we show 1-10 but this is 0-9 in array terms push @links, ($curr_page >= $start and $curr_page <= $end) ? " +$range\n" : qq!<a href="${link}start=$start&end=$end">$range</a>\n!; $current_range = $range if ($curr_page >= $start and $curr_pag +e <= $end); } return (join ' | ', @links) , $current_range; } __DATA__ Current page array[13] display range 13-18 <a href="/cgi-bin/script.pl?start=0&end=5">1-6</a> | <a href="/cgi-bin/script.pl?start=6&end=11">7-12</a> | 13-18 | <a href="/cgi-bin/script.pl?start=18&end=23">19-24</a> | <a href="/cgi-bin/script.pl?start=24&end=24">25</a>

    cheers

    tachyon

Re: dividing a hash by sets of $num
by zentara (Cardinal) on Mar 14, 2004 at 15:29 UTC
    Here is a pager method I'm using in Tk. Basically you put all the keys to be displayed into an @list, then you parse through @list pushing them into @{pager{$count}}, and incrementing $count when scalar @{pager{$count}} exceeds the desired pagesize.
    ###################################################################### +######## my $pagesize = 10; #elements per page sub setup_pager{ my $arrayref = $_[0]; #pass in @list my $new = $_[1]; #conditional for new %pager=(); #empty pager my $keytot = scalar @{$arrayref}; #print "$keytot\n"; my $key; #setup pages####################### my $count = 1; foreach $key (@{$arrayref}){ push @{$pager{$count}},$key; if(scalar @{$pager{$count}} > ($pagesize - 1) ){$count++} } ################################## if($new){&display_page($count)} else{ &display_page(1) }; } ###################################################################### +########## sub display_page{ $page = shift; my $e = shift || 1; #which entry to display, defaults to 1 #top is admin at 0 $pagetot = scalar(keys %pager); $pagerlab->configure(-text => "Page $page of $pagetot"); #blank previous thumbnail entries foreach(1..$pagesize){$h->hide('entry',$_)} #load page foreach my $key (@{$pager{$page}} ){ $ethumbs{$e}->blank; $ethumbs{$e}->read($info{$key}{'thumbnail'}); $h->itemConfigure ($e, 0, #image is read directly in Photo object above -text => $info{$key}{'comment'}, ); $h->itemConfigure($e, 1, -text => "$info{$key}{'name'}\n$info{$key}{'key'}", ); $h->show('entry',$e); $e++; } }

    I'm not really a human, but I play one on earth. flash japh
Re: dividing a hash by sets of $num
by sshfr (Beadle) on Mar 15, 2004 at 02:26 UTC