Beefy Boxes and Bandwidth Generously Provided by pair Networks
Your skill will accomplish
what the force of many cannot
 
PerlMonks  

Comparing two arrays...

by austin43 (Acolyte)
on Apr 19, 2011 at 21:28 UTC ( [id://900229]=perlquestion: print w/replies, xml ) Need Help??

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

Hello monks, I am trying to create a script that will compare two arrays, and only print values that match up. I've looked around for answers, but I can't seem to find anything comprehensive.

My first array is:
@ServicesOnMachine = `/sbin/chkconfig --list | awk '{print \$1}'`;
which contains:
NetworkManager acpid anacron atd auditd autofs avahi-daemon avahi-dnsconfd bluetooth capi conman cpuspeed crond cups dnsmasq dund firstboot gpm haldaemon hidd hplip httpd ip6tables iptables irda irqbalance iscsi iscsid isdn kudzu lvm2-monitor mcstrans mdmonitor mdmpd messagebus multipathd netconsole netfs netplugd network nfs nfslock nscd ntpd oddjobd pand pcscd portmap psacct rawdevices rdisc readahead_early readahead_later restorecond rpcgssd rpcidmapd rpcsvcgssd saslauthd sendmail smartd sshd svnserve syslog tcsd vboxadd vboxadd-service vboxadd-x11 vncserver wdaemon winbind wpa_supplicant xfs ypbind yum-updatesd
My 2nd array is:
@ServiceCheckList = ("spray", "echo", "daytime", "discard", "chargen", + "ttdb", "ypbind", "ypserv", "yppasswdd", "ypxfrd", "tooltalk", "rsta +td", "comsat", "talk", "uucp", "finger", "netstat", "systat", "rusers +", "walld", "rexd", "rje", "netbios", "lpd", "http", "gopher", "tcpmu +x", "news", "nntp", "snmp", "mail", "smtp", "pop2", "pop3", "sendmail +", "httpd");
I want to make it so if any values from the 1st and 2nd array match up, it will print the output... Probably something like....?
foreach (@ServiceCheckList eq @ServicesOnMachine) { print $_; }
Obviously this isn't it but I need something to print only matching values. Thanks in advance! :)

Replies are listed 'Best First'.
Re: Comparing two arrays...
by choroba (Cardinal) on Apr 19, 2011 at 21:34 UTC
Re: Comparing two arrays...
by jwkrahn (Abbot) on Apr 19, 2011 at 21:42 UTC
    my %ServiceCheckList; @ServiceCheckList{ qw/ spray echo daytime discard chargen ttdb ypbind ypserv yppasswdd ypxfrd tooltalk rstatd comsat talk uucp finger netstat systat rusers walld rexd rje netbios lpd http gopher tcpmux news nntp snmp mail smtp pop2 pop3 sendmail httpd / } = (); open my $PIPE, '-|', '/sbin/chkconfig', '--list' or die "Cannot open pipe from '/sbin/chkconfig' because: $!"; while ( <$PIPE> ) { chomp; print "$_\n" if exists $ServiceCheckList{ $_ }; } close $PIPE or warn $! ? "Error closing '/sbin/chkconfig' pipe: $!" : "Exit status $? from '/sbin/chkconfig'";
Re: Comparing two arrays...
by LanX (Saint) on Apr 19, 2011 at 21:36 UTC
    If your requirement is the intersection of two sets of strings, try hash-slices:

    DB<100> @a="a".."f" DB<101> @b="d".."h" DB<102> @hash{@a}=@a; DB<103> print @hash{@b} def

    If not, well it's an FAQ, for instance see Re: How do I compare two arrays? or do your own supersearch or site search with google.

    Cheers Rolf

Re: Comparing two arrays...
by wallisds (Beadle) on Apr 20, 2011 at 17:36 UTC

    I understand using grep can hinder performance but for your purposes it would work well:

    foreach my $service (@ServiceCheckList) { if (grep($service, @ServicesOnMachine)) { print "$service matches\n"; } }

    Oops! I didn't spend enough time examining the output. Lame! thanks for pointing it out. This would be better:

    foreach my $service (@ServiceCheckList) { if (grep(/^$service$/, @ServicesOnMachine)) { print "$service matches\n"; } }

    I'm learning a lot on PerlMonks! Thanks!!!
    Dawn

      did you test your code?

      I think you mean grep /^$service$/, @ServicesOnMachine or grep {$service eq $_} @ServicesOnMachine

      Cheers Rolf

        I did test it (see code below). It seemed to work for me but I see from some of the comments that it can be used in a much better way.

        #!/usr/bin/perl -w use strict; my @ServicesOnMachine = qw(NetworkManager acpid anacron atd auditd aut +ofs avahi-daemon avahi-dnsconfd bluetooth capi conman cpuspeed crond +cups dnsmasq dund firstboot gpm haldaemon hidd hplip httpd ip6tables +iptables irda irqbalance iscsi iscsid isdn kudzu lvm2-monitor mcstran +s mdmonitor mdmpd messagebus multipathd netconsole netfs netplugd net +work nfs nfslock nscd ntpd oddjobd pand pcscd portmap psacct rawdevic +es rdisc readahead_early readahead_later restorecond rpcgssd rpcidmap +d rpcsvcgssd saslauthd sendmail smartd sshd svnserve syslog tcsd vbox +add vboxadd-service vboxadd-x11 vncserver wdaemon winbind wpa_supplic +ant xfs ypbind yum-updatesd); my @ServiceCheckList = ("spray", "echo", "daytime", "discard", "charge +n", "ttdb", "ypbind", "ypserv", "yppasswdd", "ypxfrd", "tooltalk", "r +statd", "comsat", "talk", "uucp", "finger", "netstat", "systat", "rus +ers", "walld", "rexd", "rje", "netbios", "lpd", "http", "gopher", "tc +pmux", "news", "nntp", "snmp", "mail", "smtp", "pop2", "pop3", "sendm +ail", "httpd");
        foreach my $service (@ServiceCheckList) { if (grep($service, @ServicesOnMachine)) { print "$service matches\n"; } }

        Correction

        foreach my $service (@ServiceCheckList) { if (grep(/^$service$/, @ServicesOnMachine)) { print "$service matches\n"; } }

        Thanks!

      Grep is not the performance issue here. Perl grep is actually way cool and super fast.

      The performance issue here appears to me to be that you are iterating in an outer loop over each thing in @ServiceCheckList AND THEN iterating again over every element in @ServicesOnMachine for every thing in @ServiceCheckList in an inner loop. So this takes CheckList * OnMachine iterations.

      My code takes one pass through each item in CheckList and OnMachine to build the hash. Then one more time through essentially both to generate the intersection. That is (CheckList+OnMachine)*2 operations, less than (CheckList * OnMachine) operations.

      On another point, I personally prefer the grep BLOCK LIST syntax - for me, it is easier to read and understand.
      @output = grep{ TRUE OR FALSE }@input;

      If what is inside the grep BLOCK evaluates to "TRUE", pass the input to the output on the left. What is inside the grep BLOCK can be arbitrarily complex, but it all comes down to essentially "true" or "false". Perl grep could have been called "filter" because a subset of @input appears on the @output. A regex can be within the BLOCK, @output = grep{/^abc/}@input passes things that begin with "abc" from the input to the output because the regex evaluates to "true" in that case.

Re: Comparing two arrays...
by Marshall (Canon) on Apr 20, 2011 at 21:45 UTC
    The implementation of what you need is perhaps a bit easier than it might appear from the FAQ that choroba rightly points out. The second "foreach" is just a grep. Consider:

    my %count; $count{$_}++ foreach (@ServicesOnMachine, @ServiceCheckList); my @intersection = grep{$count{$_} >=2} keys %count; print "@intersection\n"; #prints: sendmail httpd ypbind

Log In?
Username:
Password:

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

How do I use this?Last hourOther CB clients
Other Users?
Others rifling through the Monastery: (4)
As of 2024-04-16 13:56 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found