grepping a list of patterns in a larger list

Discussion in 'Perl Misc' started by Udaykumar Kunapuli, May 6, 2014.

  1. Hi,

    I have 2 lists.

    As an example:
    @list1 = (1234, 345638, 3535, 93756387);
    @list2 = ("375539 Linux DONE", "1234 Linux DONE", "345638 Linux EXIT", "6384643 Linux RUN", "45234 Linux RUN", "3535 Linux DONE", "93756387 Linux DONE");

    I need to print out the list of elements in list2 where the first number part of the string does NOT exist in list1.

    I need to get a list3 from list2 where list3 looks like below
    @list3 = ("375539 Linux DONE", "6384643 Linux RUN", "45234 Linux RUN");

    None of the above first number parts in list3 exist in list1, which is how I want it to be.

    What would be the simplest way of doing this in Perl?

    Thanks,
    Uday
     
    Udaykumar Kunapuli, May 6, 2014
    #1
    1. Advertisements

  2. Udaykumar Kunapuli

    $Bill Guest

    If list1 is reasonably small, I'd just grep list2 for each item in list1:

    use strict;
    use warnings;

    my @list1 = (1234, 345638, 3535, 93756387);
    my @list2 = ("375539 Linux DONE", "1234 Linux DONE", "345638 Linux EXIT",
    "6384643 Linux RUN", "45234 Linux RUN", "3535 Linux DONE",
    "93756387 Linux DONE"
    );

    foreach my $re (@list1) {
    my @found = grep /$re/, @list2;
    print "@found\n" if @found;
    }

    __END__
     
    $Bill, May 6, 2014
    #2
    1. Advertisements

  3. Udaykumar Kunapuli

    Tim McDaniel Guest

    The better sort of reply would note that this might be a "do my
    homework for me" question and would ask what you've tried already.

    So what have you tried already? Or what have you thought about and
    not known how to do?

    I'll be kind enough, or unkind enough (in that, if it's a class,
    someone providing you with a solution is hurting your learning), to
    suggest that you consider a hash table:
    - hash1, with key = each element of @list1 and value = 1 (the value
    need not be used so it doesn't matter)
    Then go through each element of @list2, separate out the number at the
    start of the element, and see whether it's in %hash1.
     
    Tim McDaniel, May 6, 2014
    #3
  4. Udaykumar Kunapuli

    gamo Guest

    El 06/05/14 05:17, Udaykumar Kunapuli escribió:
    "45234 Linux RUN", "3535 Linux DONE", "93756387 Linux DONE");
    for $j (@list2){
    $j =~ /(\d+)\s/;
    $n = $1; # extract the number
    $ok=1;
    for $i (@list1){
    if ($i == $n){
    $ok =0;
    last;
    }
    }
    if ($ok==1){
    push @list3, $j;
    }
    }

    You ask for the simplest way.
     
    gamo, May 6, 2014
    #4
  5. Udaykumar Kunapuli

    ilovelinux Guest

    Maybe not the simplest, but to avoid programming a nested loop: create a
    regular expression of the numbers in @list1 and grep @list2 for that RE.

    my $re = join("|", map { quotemeta $_ } @list1);
    my @list3 = grep { !/$re/ } @list2;
     
    ilovelinux, May 6, 2014
    #5
  6. Udaykumar Kunapuli

    gamo Guest

    El 06/05/14 10:08, Jürgen Exner escribió:
    Ok, let's go:

    for $i (@list1){
    $h{$i}=1;
    }

    for $j (@list2){
    $j =~ /(\d+)\s/;
    $n = $1;
    unless (defined $h{$n}){
    push @list3, $j;
    }
    }
    %h = ();
     
    gamo, May 6, 2014
    #6
  7. This can be simplified somewhat with map and grep:

    %filter = map { $_, 1 } @list1;
    @list3 = grep { /^(\S+)/, !$filter{$1}; } @list2;

    The grep expression could also be written as

    !$first{(/^(\S+)/)[0]}

    I'm unsure if this should be considered a good or a bad idea.
     
    Rainer Weikusat, May 6, 2014
    #7
  8. Udaykumar Kunapuli

    Manfred Lotz Guest

    I would do it this way. If @list1 is really large one should perhaps
    think twice.

    <---------------------------snip------------------------------>
    #! /usr/bin/perl

    use strict;
    use warnings;

    my @list1 = (1234, 345638, 3535, 93756387);
    my @list2 = ("375539 Linux DONE", "1234 Linux DONE", "345638 Linux
    EXIT", "6384643 Linux RUN", "45234 Linux RUN", "3535 Linux DONE",
    "93756387 Linux DONE");


    my %hash = map { $_ => 1 } @list1;
    my @list3;

    foreach my $li ( @list2 ) {
    my @words = split /\s+/,$li;
    if ( not defined $hash{"$words[0]"} ) {
    push @list3, $li;
    }
    }

    foreach my $li ( @list3 ) {
    print "$li\n";
    }

    <---------------------------snap------------------------------>
     
    Manfred Lotz, May 6, 2014
    #8
  9. Udaykumar Kunapuli

    Tim McDaniel Guest

    People should
    use strict;
    use warnings;
    and declare all variables.

    People have posted two ways to convert a list to a hash in which the
    indexes are the members of the list. Here's the version I usually use:

    @h{@list1} = (1) x @list1;
     
    Tim McDaniel, May 6, 2014
    #9
  10. Udaykumar Kunapuli

    Tim McDaniel Guest

    Sorry -- two people, both using something of the form
    %hash1 = map { $_ => 1 } @list1;
     
    Tim McDaniel, May 6, 2014
    #10
  11. Two similar other ways would be

    ++$_ for @h{@list}

    s///1/ for @h{@list}

    If one is willing to test for 'existence' instead of truth, any
    expression can be used in front of the find, eg

    // for @h{@list}

    or

    1 for @h{@list}

    Actually, any operator which modifies its operand will do for this case, eg,

    ++@h{@list}
     
    Rainer Weikusat, May 6, 2014
    #11
  12. Udaykumar Kunapuli

    Tim McDaniel Guest

    $ perl -e 'use strict; use warnings; use Data::Dumper; my @list = (17, 19, 23); my %h; ++@h{@list}; print Dumper(\%h), "\n"'
    $VAR1 = {
    '23' => 1,
    '19' => undef,
    '17' => undef
    };
    $ perl -e 'use strict; use warnings; use Data::Dumper; my @list = (17, 19, 23); my %h; 0 for @h{@list}; print Dumper(\%h), "\n"'
    $VAR1 = {
    '23' => undef,
    '19' => undef,
    '17' => undef
    };

    OK, I don't get it. What's going on here? I don't think it could be
    autovivication eo nomine.
     
    Tim McDaniel, May 6, 2014
    #12
  13. 'Autovivification because of lvalue context', see pp_hslice in pp.c.
     
    Rainer Weikusat, May 6, 2014
    #13
  14. Udaykumar Kunapuli

    Dr.Ruud Guest

    There are many ways, for example:

    perl -Mstrict -wE'
    my @list1 = (1234, 345638, 3535, 93756387);
    my @list2 = ("375539 Linux DONE", "1234 Linux DONE"
    , "345638 Linux EXIT", "6384643 Linux RUN", "45234 Linux RUN"
    , "3535 Linux DONE", "93756387 Linux DONE");
    my $re = join "|", @list1;
    my @list3 = grep !/^(?:$re)\b/, @list2;
    '
     
    Dr.Ruud, May 13, 2014
    #14
    1. Advertisements

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 (here). After that, you can post your question and our members will help you out.