Index position of array item by string match?

Discussion in 'Perl Misc' started by Tuxedo, Nov 28, 2011.

  1. Tuxedo

    Tuxedo Guest

    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
    Tuxedo, Nov 28, 2011
    #1
    1. Advertising

  2. Tuxedo

    Tuxedo Guest

    Index position of array item by string match? (corrected)

    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
    Tuxedo, Nov 28, 2011
    #2
    1. Advertising

  3. Tuxedo <> writes:
    > 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}.
    Rainer Weikusat, Nov 28, 2011
    #3
  4. Tuxedo

    Justin C Guest

    On 2011-11-28, Tuxedo <> wrote:
    > 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.

    --
    Justin C, by the sea.
    Justin C, Nov 28, 2011
    #4
  5. Tuxedo

    J. Gleixner Guest

    Re: Index position of array item by string match? (corrected)

    On 11/28/11 16:10, Tuxedo wrote:
    > 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.
    J. Gleixner, Nov 28, 2011
    #5
  6. Tuxedo

    Tuxedo Guest

    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

    > --------------
    >
    > 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}.
    Tuxedo, Nov 28, 2011
    #6
  7. Tuxedo

    Tuxedo Guest

    Re: Index position of array item by string match? (corrected)

    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
    Tuxedo, Nov 28, 2011
    #7
  8. Tuxedo

    Tuxedo Guest

    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
    Tuxedo, Nov 28, 2011
    #8
  9. Tuxedo

    J. Gleixner Guest

    Re: Index position of array item by string match? (corrected)

    On 11/28/11 18:58, Tuxedo wrote:
    > 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];
    }
    }
    J. Gleixner, Nov 28, 2011
    #9
  10. Tuxedo <> writes:

    [...]


    > 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.
    Rainer Weikusat, Nov 28, 2011
    #10
  11. Tad McClellan <> writes:
    > Tuxedo <> wrote:


    [...]

    >> # ???
    >> # 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.
    Rainer Weikusat, Nov 28, 2011
    #11
  12. Ben Morrow <> writes:
    > Quoth Rainer Weikusat <>:
    >>
    >> --------------
    >> 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;

    >
    > ++ 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.
    Rainer Weikusat, Nov 29, 2011
    #12
  13. Tuxedo

    Willem Guest

    Ben Morrow wrote:
    )
    ) Quoth Tad McClellan <>:
    )> Rainer Weikusat <> wrote:
    )> > Tad McClellan <> writes:
    )> >> Tuxedo <> wrote:
    )> >
    )> >>> # ???
    )> >>> # 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
    Willem, Nov 30, 2011
    #13
  14. Ben Morrow <> writes:
    > Quoth Tad McClellan <>:
    >> Rainer Weikusat <> wrote:
    >> > Tad McClellan <> writes:
    >> >> Tuxedo <> wrote:
    >> >
    >> >>> # ???
    >> >>> # 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 ...).
    Rainer Weikusat, Nov 30, 2011
    #14
  15. Tad McClellan <> writes:
    > Rainer Weikusat <> wrote:
    >> Ben Morrow <> writes:
    >>> Quoth Tad McClellan <>:
    >>>> Rainer Weikusat <> wrote:
    >>>> > Tad McClellan <> writes:
    >>>> >> Tuxedo <> wrote:
    >>>> >
    >>>> >>> # ???
    >>>> >>> # 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.
    Rainer Weikusat, Nov 30, 2011
    #15
    1. Advertising

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

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Jon Perez
    Replies:
    1
    Views:
    1,056
    Peter Otten
    May 28, 2004
  2. Ook
    Replies:
    8
    Views:
    397
    Victor Bazarov
    Mar 17, 2007
  3. Old Echo
    Replies:
    1
    Views:
    174
    Adam Shelly
    Sep 4, 2008
  4. Tomasz Chmielewski

    sorting index-15, index-9, index-110 "the human way"?

    Tomasz Chmielewski, Mar 4, 2008, in forum: Perl Misc
    Replies:
    4
    Views:
    271
    Tomasz Chmielewski
    Mar 4, 2008
  5. Timmy
    Replies:
    3
    Views:
    128
    Timmy
    Nov 4, 2005
Loading...

Share This Page