1

I am trying to find a way to get an index of an element in an array that partially matches a certain patten. Let's say I have an array with values

Maria likes tomatoes,
Sonia likes plums,
Andrew likes oranges

If my search term is plums, I will get 1 returned as index. Thank you!

1
  • Iterate over the array and use pattern matching to find if yourstring matches. Commented Feb 24, 2015 at 14:32

2 Answers 2

6

Quick search didn't find a dupe, but I'm sure there is one. Meanwhile:

To find elements of an array that meet a certain condition, you use grep. If you want the indexes instead of the elements.. well, Perl 6 added a grep-index method to handle that case, but in Perl 5 the easiest way is to change the target of grep. That is, instead of running it on the original array, run it on a list of indexes - just with a condition that references the original array. In your case, that might look like this:

my @array = ( 'Maria likes tomatoes', 
              'Sonia likes plums', 
              'Andrew likes oranges');

grep { $array[$_] =~ /plums/ } 0..$#array;    # 1

Relevant bits:

  • $#array returns the index of the last element of @array.
  • m..n generates a range of values between m and n (inclusive); in list context that becomes a list of those values.
  • grep { code } list returns the elements of list for which code produces a true value when the special variable $_ is set to the element.

These sorts of expressions read most easily from right to left. So, first we generate a list of all the indexes of the original array (0..$#array), then we use grep to test each index (represented by $_) to see if the corresponding element of @array ($array[$_]) matches (~=) the regular expression /plums/.

If it does, that index is included in the list returned by the grep; if not, it's left out. So the end result is a list of only those indexes for which the condition is true. In this case, that list contains only the value 1.

Added to reply to your comment: It's important to note that the return value of grep is normally a list of matching elements, even if there is only one match. If you assign the result to an array (e.g. with my @indexes = grep...), the array will contain all the matching values. However, grep is context-sensitive, and if you call it in scalar context (e.g. by assigning its return value to a scalar variable with something like my $count = grep...), you'll instead only get a number telling you how many matches there were. You might want to take a look at this tutorial on context sensitivity in Perl.

Sign up to request clarification or add additional context in comments.

4 Comments

Thank you, Mark! While when printing I get the correct value with this code, I can't store it. If I assign it to a variable I get 1 as a result, regardless of what the index is. Do you know what problem is at hand here?
grep will be returning a list, so if you have multiple hits, you'll get multiple results. You can assign it with my @indicies = grep .....
@MarkReed: “The return value of grep is a list of matching elements ...” That's not really true. A list in scalar context evaluates to the last element of the list. It is grep itself that is contexts sensitive, and returns a count of matching elements in scalar context. That is different from a subroutine that always returns a list.
@Sobrique - Even better would be to use first from the core List::Util module because it short-circuits on finding item: my $first_match = first { ...
3

This is what firstidx from List::MoreUtils is for.

#!/usr/bin/perl

use strict;
use warnings;
use 5.010;

use List::MoreUtils 'firstidx';

my @array = ('Maria likes tomatoes',
             'Sonia likes plums',
             'Andrew likes oranges');

say firstidx { /plums/ } @array;

Update: I see that draegtun has answered your comment about getting multiple indexes. But I wonder why you couldn't just browse the List::MoreUtils documentation to see if there was a useful-looking function in there.

2 Comments

What if you want the indexes of all the matching elements, not just the first (or last, since List::MoreUtils also offers lastidx)?
@MarkReed - see indexes in List::MoreUtils to get indexes of all matching elements - metacpan.org/pod/List::MoreUtils#indexes-BLOCK-LIST

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.