Index position of array item by string match?

T

Tuxedo

What is the best/simplest way to create the following clickthrough
procedure?

A perl script (display.pl) has a cgi-parameter that will show an image, by
accessing for example display.pl?img=img_xyz.jpg

use warnings;
use strict;

use CGI qw(param);
my $img = param("img");

print "Content-Type: text/html\n\n";

my @images = ("image_001.jpg",
"image_002.jpg",
"image_xyz.jpg",
"image_zzz.jpg);

# ???
# find the index position of by matching $img string
# to print out $link_before and $link_after below
# ???

print "<a href=display.pl$link_before>";
print "<img src=$img>";
print "<a href=display.pl$link_after>";

------------------

The image names are kept in an array but not necessary in a numerical order
name form.

How can the corresponding index number of the matching $img cgi-string be
found and extracted in order to print out the link to the next
($link_after) and previous image ($link_before) items found in the array?

Of course, this would only be functional as long as each array item has a
unique name, which they would have.

The html output when accessing display.pl?img=img_xyz.jpg could be:

<a href=display.pl?img=image_002.jpg>previous</a>
<img src=image_xyz.jpg>
<a href=display.pl?img=image_zzz.jpg>next</a>

But while displaying either the first or last image, the link value could
simply loop to the end or the start of the array.

Alternatively, the opening and closing <a..></a> could be omitted when the
position is either at the beginning or the end of the array. So for
example, if accessing display.pl?img=image_zzz.jpg, the output can then be:

<a href=display.pl?img=image_xyz.jpg>previous</a>
<img src=image_zzz.jpg>
next

Any ideas how to best do the above would be appreciated.

Many thanks!

Tuxedo
 
T

Tuxedo

Sorry, there were some errors in "img=img.." which should say "img=image.."
in the previous post, which have been corrected in the below version:

What is the best/simplest way to create the following clickthrough
procedure?

A perl script (display.pl) has a cgi-parameter that will show an image, by
accessing for example display.pl?img=image_xyz.jpg

use warnings;
use strict;

use CGI qw(param);
my $img = param("img");

print "Content-Type: text/html\n\n";

my @images = ("image_001.jpg",
"image_002.jpg",
"image_xyz.jpg",
"image_zzz.jpg);

# ???
# find the index position of matching $img string
# to print out $link_before and $link_after below
# ???

print "<a href=display.pl$link_before>";
print "<img src=$img>";
print "<a href=display.pl$link_after>";

------------------

The image names are kept in an array but not necessary in a numerical order
name form.

How can the corresponding index number of the matching $img cgi-string be
found and extracted in order to print out the link to the next
($link_after) and previous image ($link_before) items found in the array?

Of course, this would only be functional as long as each array item has a
unique name, which they would have.

The html output when accessing display.pl?img=image_xyz.jpg could be:

<a href=display.pl?img=image_002.jpg>previous</a>
<img src=image_xyz.jpg>
<a href=display.pl?img=image_zzz.jpg>next</a>

But while displaying either the first or last image, the link value could
simply loop to the end or the start of the array.

Alternatively, the opening and closing <a..></a> could be omitted when the
position is either at the beginning or the end of the array. So for
example, if accessing display.pl?img=image_zzz.jpg, the output can then be:

<a href=display.pl?img=image_xyz.jpg>previous</a>
<img src=image_zzz.jpg>
next

Any ideas how to best do the above would be appreciated.

Many thanks!

Tuxedo
 
R

Rainer Weikusat

Tuxedo said:
A perl script (display.pl) has a cgi-parameter that will show an image, by
accessing for example display.pl?img=img_xyz.jpg

use warnings;
use strict;

use CGI qw(param);
my $img = param("img");

print "Content-Type: text/html\n\n";

my @images = ("image_001.jpg",
"image_002.jpg",
"image_xyz.jpg",
"image_zzz.jpg);

# ???
# find the index position of by matching $img string
# to print out $link_before and $link_after below
# ???

print "<a href=display.pl$link_before>";
print "<img src=$img>";
print "<a href=display.pl$link_after>";

------------------

The image names are kept in an array but not necessary in a numerical order
name form.

How can the corresponding index number of the matching $img cgi-string be
found and extracted in order to print out the link to the next
($link_after) and previous image ($link_before) items found in the
array?

The simplest idea would be to scan the image array:

--------------
my $ndx;

for (@images) {
last if $_ eq $img;
++$ndx;
}

printf('<a href="display.pl?%s">', $images[$ndx - 1]) if $ndx;
printf('<a href="display.pl?%s">', $images[$ndx + 1]) if $ndx < $#images;
--------------

NB: If you're afraid of pointless warnings, make that my $ndx = 0;

The obvious other idea would be to use an image hash:

my ($ndx, %images);

$ndx = 0;
%images = map { $_ => $ndx++ } @images;

In this case, the current index would be in $images{$img}.
 
J

Justin C

What is the best/simplest way to create the following clickthrough
procedure?

A perl script (display.pl) has a cgi-parameter that will show an image, by
accessing for example display.pl?img=img_xyz.jpg

use warnings;
use strict;

use CGI qw(param);
my $img = param("img");

print "Content-Type: text/html\n\n";

my @images = ("image_001.jpg",
"image_002.jpg",
"image_xyz.jpg",
"image_zzz.jpg);

# ???
# find the index position of by matching $img string
# to print out $link_before and $link_after below
# ???

print "<a href=display.pl$link_before>";
print "<img src=$img>";
print "<a href=display.pl$link_after>";

------------------

The image names are kept in an array but not necessary in a numerical order
name form.

How can the corresponding index number of the matching $img cgi-string be
found and extracted in order to print out the link to the next
($link_after) and previous image ($link_before) items found in the array?

Don't return the name in the link, but the index number. Previous and
next are then as simple as $link -1 and $link +1.


Justin.
 
J

J. Gleixner

Sorry, there were some errors in "img=img.." which should say "img=image.."
in the previous post, which have been corrected in the below version:

What is the best/simplest way to create the following clickthrough
procedure?

A perl script (display.pl) has a cgi-parameter that will show an image, by
accessing for example display.pl?img=image_xyz.jpg

use warnings;
use strict;

use CGI qw(param);
my $img = param("img");

print "Content-Type: text/html\n\n";
There's a header() method in CGI?? Much cleaner.
my @images = ("image_001.jpg",
"image_002.jpg",
"image_xyz.jpg",
"image_zzz.jpg);

Provide code that's correct.
# ???
# find the index position of matching $img string
# to print out $link_before and $link_after below
# ???

print "<a href=display.pl$link_before>";
print "<img src=$img>";
print "<a href=display.pl$link_after>";

------------------

The image names are kept in an array but not necessary in a numerical order
name form.

How can the corresponding index number of the matching $img cgi-string be
found and extracted in order to print out the link to the next
($link_after) and previous image ($link_before) items found in the array?

Of course, this would only be functional as long as each array item has a
unique name, which they would have.

The html output when accessing display.pl?img=image_xyz.jpg could be:

<a href=display.pl?img=image_002.jpg>previous</a>
<img src=image_xyz.jpg>
<a href=display.pl?img=image_zzz.jpg>next</a>

But while displaying either the first or last image, the link value could
simply loop to the end or the start of the array.

Alternatively, the opening and closing<a..></a> could be omitted when the
position is either at the beginning or the end of the array. So for
example, if accessing display.pl?img=image_zzz.jpg, the output can then be:

<a href=display.pl?img=image_xyz.jpg>previous</a>
<img src=image_zzz.jpg>
next

Any ideas how to best do the above would be appreciated.

Create a subroutine that will iterate over @images, returning the index
of the current param('img'). The code for that iteration could be
something like:


for my $i ( 0 .. $#images )
{
return $i if $img eq $images[$i];
}



Call that subroutine and then print the HTML, or don't print HTML
if the index is 0 or the last index.

print "something" unless $index == 0;

Using CGI's a, img, and header methods will help clean up the code.
 
T

Tuxedo

Rainer Weikusat wrote:

[...]

The simplest idea would be to scan the image array:

--------------
my $ndx;

for (@images) {
last if $_ eq $img;
++$ndx;
}

printf('<a href="display.pl?%s">', $images[$ndx - 1]) if $ndx;
printf('<a href="display.pl?%s">', $images[$ndx + 1]) if $ndx < $#images;

Thanks for the above example, it works nicely in that when the first image
is viewed there's no 'previous' link, or when the last image is viewed
there is no next link, or when an image somewhere between is viewed, both
the previous and next links appear.

This is my slightly modified version:

use CGI qw(param);
my $img = param("img");

my @images = ("image_001.jpg",
"image_002.jpg",
"image_003.jpg",
"image_004.jpg");

my $ndx;

for (@images) {
last if $_ eq $img;
++$ndx;
}

printf('<a href="display.pl?%s">previous',$images[$ndx - 1]) if $ndx;
print "<img src=$img>";
printf('<a href="display.pl?%s">next', $images[$ndx + 1]) if $ndx <
$#images;

How would the closing </a>'s be included in the above procedure? I had
forgotten these in the print statements in my previous mock-up.

Also, instead of displaying nothing if there is no previous or next image,
how can an alternative placeholder string be returned, such as printing
'previous' when displaying image_001.jpg but without the enclosing <a
...></a>, or printing 'next' without the enclosing <a..></a> when displaying
the last? Sorry, I don't fully see through the "printf(... if $indx"
procedure.

Thanks again, I will try the hash method next.

Tuxedo
 
T

Tuxedo

J. Gleixner wrote:

[..]
Provide code that's correct.

Yes, thanks for pointing out the missing quotation mark.
for my $i ( 0 .. $#images )
{
return $i if $img eq $images[$i];
}



Call that subroutine and then print the HTML, or don't print HTML
if the index is 0 or the last index.

print "something" unless $index == 0;

Using CGI's a, img, and header methods will help clean up the code.

Any chance of a few more pointers to help fill out the blanks? I'm not
quite how to turn the above ideas into a working example.

Many thanks,
Tuxedo
 
T

Tuxedo

Tuxedo wrote:

[...]
printf('<a href="display.pl?%s">previous',$images[$ndx - 1]) if $ndx;
How would the closing </a>'s be included in the above procedure? I had
forgotten these in the print statements in my previous mock-up.

Sorry, I think I've been staring at the screen too long, the missing </a>
obviously goes straight after previous</a>'.. or .. next</a>', eg.:
printf('<a href="display.pl?%s">previous</a>',$images[$ndx - 1]) if $ndx;

That's even plain html....

Tuxedo
 
J

J. Gleixner

J. Gleixner wrote:

[..]
Provide code that's correct.

Yes, thanks for pointing out the missing quotation mark.
for my $i ( 0 .. $#images )
{
return $i if $img eq $images[$i];
}



Call that subroutine and then print the HTML, or don't print HTML
if the index is 0 or the last index.

print "something" unless $index == 0;

Using CGI's a, img, and header methods will help clean up the code.

Any chance of a few more pointers to help fill out the blanks? I'm not
quite how to turn the above ideas into a working example.

use CGI qw( param a header img);
my @images = qw(
image_001.jpg
image_002.jpg
image_xyz.jpg
image_zzz.jpg
);

my $cur_index = find_index( param( 'img' ) );

print header;
print a( { href => "display.pl?img=$images[ $cur_index-1 ]" },
'previous'
) unless $cur_index == 0;
#etc.

sub find_index
{
my $img = shift;

for my $index ( 0 .. $#images )
{
return $index if $img eq $images[$i];
}
}
 
R

Rainer Weikusat

[...]

Also, instead of displaying nothing if there is no previous or next image,
how can an alternative placeholder string be returned, such as printing
'previous' when displaying image_001.jpg but without the enclosing <a
..></a>, or printing 'next' without the enclosing <a..></a> when displaying
the last? Sorry, I don't fully see through the "printf(... if $indx"
procedure.

The 'if $ndx' and 'if $ndx < $#images' are so-called statement
modifiers which can be used to execute a single statement
conditionally without creating a block and tearing it down again.
For more complicated choices, the 'full' syntax has to be used, eg

if ($ndx) {
# print image link
} else {
# alternate output
}
Thanks again, I will try the hash method next.

While hashes are usually the way to go when doing 'by-name' lookups,
this would be suboptimal here: Constructing the hash requires
traversing the entire array, calculating the hash value of each string
and creating a slighlty more complicated data structure than the
original array based on this information. For the single lookup,
another hash value needs to be calculated and finally a string
comparison has to be performed in order to determine if the entry
which was found is the one which was supposed to be
located. Traversing the array once while looking for the sought after
string directly, which requires a partial string comparison for each
mismatch and a complete one for the entry in question, is going to be
cheaper.
 
R

Rainer Weikusat

Ben Morrow said:
Quoth Rainer Weikusat said:
--------------
my $ndx;

for (@images) {
last if $_ eq $img;
++$ndx;
}

printf('<a href="display.pl?%s">', $images[$ndx - 1]) if $ndx;
printf('<a href="display.pl?%s">', $images[$ndx + 1]) if $ndx < $#images;

++ doesn't warn about undef, because that would be irritating.

The second printf statement should generate two of them if $img was
equal to the first image name in the array.
 
W

Willem

Ben Morrow wrote:
)
) Quoth Tad McClellan <[email protected]>:
)> >
)> >>> # ???
)> >>> # find the index position of by matching $img string
)> >>
)> >>
)> >> my($i) = grep $img eq $images[$_], 0..$#images;
)> >
)> > This is bad because it always compares the input name to all names in
)> > the array.
)>
)> Yes, I know.
)>
)> The best way and the simplest way were mutually exclusive,
)> so I had to choose one.
)
) In any case 'best' is a vague term. The grep is simple, easy to
) understand, and an obvious solution to anyone familiar with Perl. Under
) many circumstances that's 'better' than a more complicated solution that
) is marginally more efficient.

How about:

use List::Util 'first';
my $i = first $img eq $images[$_], 0..$#images;


SaSW, Willem
--
Disclaimer: I am in no way responsible for any of the statements
made in the above text. For all I know I might be
drugged or something..
No I'm not paranoid. You all think I'm paranoid, don't you !
#EOT
 
R

Rainer Weikusat

Ben Morrow said:
Quoth Tad McClellan said:
Rainer Weikusat said:
# ???
# find the index position of by matching $img string


my($i) = grep $img eq $images[$_], 0..$#images;

This is bad because it always compares the input name to all names in
the array.

Yes, I know.

The best way and the simplest way were mutually exclusive,
so I had to choose one.

In any case 'best' is a vague term. The grep is simple, easy to
understand, and an obvious solution to anyone familiar with Perl.
Under many circumstances that's 'better' than a more complicated
solution that is marginally more efficient.

The original problem was 'find the index of a particular array
element'. The problem solved by the grep statement is 'find all
elements of some sequence of numbers which happen to be the index of a
certain array element' and - as an additional contortion - a list
assignment is required on the LHS to work around the fact that grep
returns an item count in scalar context, IOW, it is neither a
particularly sensible approach from a technical standpoint nor
'simple' because it does the opposite of what was asked for.

Insofar 'use the language in ways bound to surprise people' is OK, it
isn't even a particular 'short' solution, cf

$_ eq $img && last || ++$ndx for @images;

It is very probable that this can be condensed even more by someone
who is really into 'steganographic coding' (there's surely an absurd
amount of whitespace in this statement solely intended to make it more
legible ...).
 
R

Rainer Weikusat

Tad McClellan said:
Rainer Weikusat said:
Ben Morrow said:
Quoth Tad McClellan <[email protected]>:

# ???
# find the index position of by matching $img string


my($i) = grep $img eq $images[$_], 0..$#images;

This is bad because it always compares the input name to all names in
the array.

Yes, I know.

The best way and the simplest way were mutually exclusive,
so I had to choose one.

In any case 'best' is a vague term. The grep is simple, easy to
understand, and an obvious solution to anyone familiar with Perl.
Under many circumstances that's 'better' than a more complicated
solution that is marginally more efficient.

The original problem was 'find the index of a particular array
element'.

The code I posted finds the index of a particular array element.

.... and the criticism I posted contained somewhat more text than the
single sentence you quoted.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,755
Messages
2,569,536
Members
45,014
Latest member
BiancaFix3

Latest Threads

Top