Beefy Boxes and Bandwidth Generously Provided by pair Networks
Pathologically Eclectic Rubbish Lister

Using map and grep to Sort one list using another list

by AntsPants (Novice)
on Feb 05, 2007 at 12:51 UTC ( #598282=perlquestion: print w/replies, xml ) Need Help??
AntsPants has asked for the wisdom of the Perl Monks concerning the following question:

Can I use map instead of the foreach in this bit of code? i have two lists. One has the keys (@keys) I'd like to look for in the other list (@records). The records that have the key are passed through to a @result list. If the result list is non-empty, it goes to the final list as the @result list may be overwritten in the next iteration. Or, is there a totally better alforithm to do this? I have googled and looked on this site before posting but nothing stood out and hit me in the face but I'm sure a more elegant perl way of doing it exists ;)
my @keys = ( qw|a e i o u| ); my @records = (); push @records, '1|2|3|d|4'; push @records, '1|2|3|a|4'; push @records, '1|2|3|d|4'; push @records, '1|2|3|o|4'; my @final = (); my @result = (); my $re = ''; foreach my $key ( @keys ) { @result = grep{ m/^\d\|\d\|\d\|$key\|\d$/ } @records; push @final, [ @result ] if @result; } print map{ "@{ $final[$_] }\n" } 0..$#final;
Merci bien, Perl Monkers!!

Replies are listed 'Best First'.
Re: Using map and grep to Sort one list using another list
by davorg (Chancellor) on Feb 05, 2007 at 13:28 UTC

    I think the (ahem!) key here is to convert your @keys array into a hash to make it easier to check for the existance of keys in your data line.

    my @keys = ( qw|a e i o u| ); my %keys = map { $_ => 1 } @keys; my @records = ( '1|2|3|d|4', '1|2|3|a|4', '1|2|3|d|4', '1|2|3|o|4', ); my @final; my @result; foreach (@records) { if ($keys{ (split /\|/)[3] }) { push @result, $_; } } print map { "$_\n" } @result;
      I agree but this morning I spoke to the person who has this problem and they said they wanted to keep the code as lists!!! Will have another friendly chat with them ;)
Re: Using map and grep to Sort one list using another list
by shmem (Chancellor) on Feb 05, 2007 at 13:16 UTC
    Sure you can use map:
    my @final = grep {@$_} map { my $key = $_; [ grep{ m/^\d\|\d\|\d\|$key\|\d$/ } @records ] } @keys;

    But I am missing the 'sort' bit of the title in your code...


    _($_=" "x(1<<5)."?\n".q·/)Oo.  G°\        /
                                  /\_¯/(q    /
    ----------------------------  \__(m.====·.(_("always off the crowd"))."·
    ");sub _{s./.($e="'Itrs `mnsgdq Gdbj O`qkdq")=~y/"-y/#-z/;$e.e && print}
      The sort is a mistake. Just keeping you on your toes. Now, no one's gonna believe this but ......... I'm sure while trying to solve this problem I wrote the following code
      my @keys = ( qw|a e i o u| ); my @records = (); push @records, '1|2|3|d|4'; push @records, '1|2|3|a|4'; push @records, '1|2|3|d|4'; push @records, '1|2|3|o|4'; my @final = (); my @result = (); @result = map { my $index = $_; grep{ m/^\d\|\d\|\d\|$keys[$index]\|\d$/ } @records } 0..$#keys; print map{ "$result[$_]\n" } 0..$#result
      which didn;t work. And while replying to your soln, I just re-ran that code and it worked!!!!!!! Hmmmmmmmmmm. Thank you all for replying anyway. I feel such a fool. -Ants
Re: Using map and grep to Sort one list using another list
by wfsp (Abbot) on Feb 05, 2007 at 13:17 UTC
    Here's my go with grep. If you put your keys into a hash you can use exists to see if it's one we want.
    #!C:/Perl/bin/perl.exe use strict; use warnings; my %keys = ( a => undef, e => undef, i => undef, o => undef, u => undef, ); my @records = qw{ 1|2|3|d|4 1|2|3|a|4 1|2|3|d|4 1|2|3|o|4 }; my @final = grep { my @flds = split '\|', $_; my $third = $flds[3]; exists $keys{$third} } @records; print "@final\n";
    You could make that shorter but this way gives you a better idea of what's happening. output:
    1|2|3|a|4 1|2|3|o|4
Re: Using map and grep to Sort one list using another list
by RMGir (Prior) on Feb 05, 2007 at 13:20 UTC
    Interesting problem. Maybe you could do something with a hash for your keys? This doesn't completely match your spec, although it matches your example. Perhaps you can adapt this for your needs...
    my %keys = ( a=>1, e=>2, i=>3, o=>4, u=>5, ); my @records = (); push @records, '1|2|3|d|4'; push @records, '1|2|3|a|4'; push @records, '1|2|3|d|4'; push @records, '1|2|3|o|4'; my @final = (); my @result = (); my $re = ''; map {my @flds=split /\|/; push @{$final[$keys{$flds[3]}||0]},$_} @reco +rds; # note that entry 0 is where the unmatched elements wind up... print map{ "@{ $final[$_] }\n" } grep defined $final[$_],1..$#final;
    Maps used only for their side effects are kinda wierd, though. I'd replace the map with a foreach(@records) block so it's clearer what you're doing.
    foreach(@records) { my @flds=split /\|/; push @{$final[$keys{$flds[3]}||0]},$_; }

Re: Using map and grep to Sort one list using another list
by Moron (Curate) on Feb 05, 2007 at 13:43 UTC
    Do you mean like this?
    my @result = map { my $key = $_; grep m/^\d\|\d\|\d\|$key\|\d$/, @records } @keys +;


    Free your mind

      that is what I meant and that is what I tried in testing. see reply to first post ;) As I said, I feel an idiot!!
      You will have undefined values in your @result array.

      the above is plain wrong--


        I don't see that happening. Perhaps I have missed something.

        use strict; use warnings; use Data::Dumper; my @keys = qw{a e i o u}; my @records = qw{ 1|2|3|d|4 1|2|3|a|4 1|2|3|d|4 1|2|3|o|4}; my @result = map { my $key = $_; grep { m{^(?:\d\|){3}$key\|\d$} } @records } @keys; my $dd = Data::Dumper->new([\@result], [qw{*result}]); print $dd->Dumpxs();


        @result = ( '1|2|3|a|4', '1|2|3|o|4' );



        My take on this was rather that when the grep fails to produce a match, it returns an empty list to map which then operates on no extra entries - i.e. doing nothing rather than constructing an undefined value.


        Free your mind

Log In?

What's my password?
Create A New User
Node Status?
node history
Node Type: perlquestion [id://598282]
Approved by Corion
[1nickt]: Discipulus, Corion, try this: D.A. Golden's blog
[Lady_Aleena]: Your Mother, that's the command line grep, not perl's grep.
[Your Mother]: …how on Earth could Perl’s grep recurse?
[Tanktalus]: perldigious: I'm not looking to get rich. I'm looking for interesting work, with good continuity of employment, and maintenance of our current lifestyle. (An improvement wouldn't be bad, either, but that's not a requirement ;) )
erix enjoys the confusion++
[Your Mother]: :P
[Tanktalus]: Without confusion, I'd be out of a job ;)
[Tanktalus]: Already. :D
[Lady_Aleena]: Your Mother, I wish it did have a way to put in a directory to search.
[Your Mother]: That’s silly. It’s a string op tool.

How do I use this? | Other CB clients
Other Users?
Others exploiting the Monastery: (11)
As of 2017-05-23 19:33 GMT
Find Nodes?
    Voting Booth?