Beefy Boxes and Bandwidth Generously Provided by pair Networks
There's more than one way to do things
 
PerlMonks  

Multi @array searches

by akm2 (Scribe)
on Mar 22, 2001 at 18:22 UTC ( [id://66334]=perlquestion: print w/replies, xml ) Need Help??

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

I am using:

sub search { my $terms = shift; my $pattern = join "|", split " ", $terms; my $case = $FORM{case} eq 'insensitive'?"(?i)":""; $pattern = qr/$case$pattern/; my @matches = grep { $names[$_] =~ /$pattern/ } 0..$#names; return \@matches; }

in order to find matches in @names. I have tried every way I can think of to make the code search @names and @desc as well. I want the results of both searches stored in the same array. Then I can weed out the duplicates.

Replies are listed 'Best First'.
Re: Multi @array searches
by OeufMayo (Curate) on Mar 22, 2001 at 18:33 UTC

    I don't see where your are using the @desc array in your code, but here's a small snippet demonstrating the use of grep with several arrays:

    @a = (1,2,3,4,5); @b = (10,11,12,13,14,15); @odd = grep {$_ % 2} (@a, @b); # @odd = (1,3,5,11,13,15)

    What is going on here is that perl 'flattens' both arrays into one and feed the grep with this resulting flattened array.

    <kbd>--
    my $OeufMayo = new PerlMonger::Paris({http => 'paris.mongueurs.net'});</kbd>
Re: Multi @array searches
by arturo (Vicar) on Mar 22, 2001 at 18:50 UTC

    If you want to search two arrays and put the indices of the matching results from both into one array, you might need a way of keeping track of which array each stored index comes from (how do you know if this index corresponds to a match in @names, or in @desc, or in both?). Let's say you search @names first and @desc second, or you use OeufMayo's flattening approach: you might end up with the list (1,3,5,6,9,2,6,7). How do you know where the indices for @names leaves off and the indices of matching @desc entries begin? One answer is to return two lists (an array that consists of two anonymous arrays: the list of matches from @names, and the list of matches from @desc). Alternately, you could label which was which with a hash that consists of two anonymous arrays: so, with the above example, that hash would look like:

    %matches = ( name=>[1, 3,5,6,9], desc=>[2,6,7] );
    Either way, your search code wouldn't need to be modified much. Here's the hashy approach:
    my %matches; $matches{name} = [ grep { $names[$_] =~/$pattern/ } 0 ..$#names ]; $matches{desc} = [ grep { $desc[$_] =~/$pattern/} 0.. $#desc];

    And of course you would return \%matches instead of \@matches.

    But it might be even simpler than this: if, as I suspect from your desire to remove duplicates, both arrays are part of a larger data structure (such that for each name, there is a corresponding description) then you can stick with the current approach, slightly modified. Simply change that grep line to grab the matches from either array:

    my @matches = grep { $names[$_] =~ /$pattern/ || $desc[$_] =~/$pattern/ } 0 .. $#names;

    which will also solve the problem of weeding out the duplicates.

    HTH.

    Philosophy can be made out of anything. Or less -- Jerry A. Fodor

      my @matches = grep { $names[$_] =~ /$pattern/ || $desc[$_] =~/$pattern/ } 0 .. $#names;

      Shouldnt it read:

      my @matches = grep { $names[$_] =~ /$pattern/ || $desc[$_] =~/$pattern/ } 0 .. $#desc;

      If not, why not?

        Recall that 0 .. $#array; gives you a list of all the values between 0 and the maximum index of @array, or, in other words, the list of the indexes of @array.

        That bit of code assumes (and I made this assumption explicit) that the members of @names map 1:1 onto members of @desc; and if that is true, then

        0.. $#names
        and
        0 .. $#desc

        yield up the same list, so either is acceptable.

        HTH!

        Philosophy can be made out of anything. Or less -- Jerry A. Fodor

Re: Multi @array searches
by jorg (Friar) on Mar 22, 2001 at 22:13 UTC
    besides the point but your
    my $pattern = join "|", split " ", $terms;

    is better written as my $terms =~ tr/ /|/;
    as split on one thing and join with another is effectively a substition

      Those two solutions differ quite a bit. Something closer to the original would be:

      $terms =~ s/^\s*//; $terms =~ s/\s*$//; $terms =~ s/\s+/|/g;
      because split " " actually splits on any amount of whitespace while ignoring both leading and trailing spaces.

      Of course, if you can guarantee that the input has no lead, trailing, nor repeated spaces (and no zero-width terms), then your solution would work.

              - tye (but my friends call me "Tye")
        subtle difference but very true tye, didn't think of that one!
        at least my solution is correct 'ceteris paribus' .. probably never the best assumption to make, but hey it's getting late in the day :)

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://66334]
Approved by root
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others drinking their drinks and smoking their pipes about the Monastery: (5)
As of 2024-03-29 09:09 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found