Question

Passing arrays in Perl

Asked by: Mike_Siegel

I'm trying to return an array of "shared" members between two arrays (strings).

Now my subroutine seems to work, but I can't read the return array.

I suspect I'm passing a pointer to an array rather than an array, or something similar... but this is practically right from the textbook:
http://www.unix.org.ua/orelly/perl/cookbook/ch10_06.htm

Any advice would be great, not much of a programmer!

here's the call:
 
@sharemem = SharedMembers(\@grparray1,\@grparray2);
print "Shared mem @sharedmem[0]\n";

the subroutine:

sub SharedMembers {
   my($arr1, $arr2) = @_;
   my @arr3;
   my $n = 0;

   for ($i=0;$i < @$arr1; $i++)
   {
       
       for ($j=0; $j < @$arr2; $j++)
          {
      
            if($arr1->[$i] eq $arr2->[$j])
            {
                $arr3[$n] = ($arr3[$n],$arr1->[$i]);
                $n++;
               print "Match on $arr1->[$i] $arr2->[$j]\n";
            }
          }
   }
   print "arr3x0 @arr3[0]\n";
   return @arr3;
}

the output:

Match on Local Admins Local Admins
Match on XXX Class B XXX Class B
Match on Domain Users Domain Users
Match on XXX All XXX All
Match on xxx xxx
Match on xxxc xxxc
arr3x0 Local Admins
Shared mem

What I'm looking for is
Shared mem Local Admins :(

This Question has been solved and asker verified All Experts Exchange premium technology solutions are available to subscription members.

Subscribe now for full access to Experts Exchange and get

Instant Access to this Solution

  • Plus...
  • 30 Day FREE access, no risk, no obligation
  • Collaborate with the world's top tech experts
  • Unlimited access to our exclusive solution database
  • Never be left without tech help again

Subscribe Now

Asked On
2005-02-03 at 09:11:30ID21300572
Tags

perl

,

array

,

passing

Topic

Perl Programming Language

Participating Experts
4
Points
350
Comments
7

Trusted by hundreds of thousands everyday for fast, accurate and reliable tech support.

  • "The time we save is the biggest benefit of Experts Exchange to Warner Bros. What could take multiple guys 2 hours or more each to find is accessed in around 15 minutes on Experts Exchange." Mike Kapnisakis, Warner Bros.
  • "Our team likes having a resource that is more secure than just using Google and most experts using this service really know their stuff. It's nice to look here first versus using Google." Dayna Sellner, Lockheed Martin
  • "Anytime that I've been stumped with a problem, 9 out of 10 times Experts Exchange has either the accepted solution or an open discussion of the potential solution to the problem." Kenny Red, eBay Inc.

See what Experts Exchange can do for you.

Got a question?

We've got the answer.

Experts Exchange has been collecting answers to technology questions since 1996…3 million and counting! If you have a question, chances are we already have your answer.

Screenshot of Experts Exchange Knowledgebase

Need individual assistance?

Our experts are ready to help.

If you can't find the exact answer you're looking for, ask our exclusive community of 50,000 experts. You’ll get a personalized answer from a trusted professional.

Screenshot of Experts Exchange Knowledgebase

Want to learn from the best?

Read articles from industry experts.

Thousands of free tech tips, tricks, how-to’s and tutorials are available in our peer reviewed articles section. See for yourself how smart our experts are, no login required.

Screenshot of an Article

Working on a long term project?

Store your work and research.

Save solutions to your questions, answers you’ve discovered through searching plus helpful articles in your personal knowledgebase for easy future access.

Screenshot of Experts Exchange Knowledgebase

Access the answers to your technology questions today.

Subscribe Now

30-day free trial. Register in 60 seconds.

What Makes Experts Exchange Unique?

Members of the expert community talk about why the experience at Experts Exchange is different than what you will find anywhere else.

Trusted by the world's most respected brands.

image of each brand's logo

Faithfully serving IT professionals since 1996.

Experts Exchange Logo

Try it out and discover for yourself.

Subscribe Now

30-day free trial. Register in 60 seconds.

Related Solutions

  1. Perl Arrays Problem...
    First if all, I am not a Perl junkie. In fact, I am just learning the language. Soooooo, it figures that something that may be simple to the rest of you is about to drive me nuts. According to everything I have read in books and online, what I have done below SHOULD work but ...
  2. @_ in PERL
    Hi I'm new to Perl (but experienced in VB and more recently C) and am modifying some existing code. Can anyone please tell me what the @_ and ($OUT) means in this sub routine? sub setOutput(@) { ($OUT) = @_; } Am I right in thinking that the @ defines a variable a...

Free Tech Articles

  1. WARNING: 5 Reasons why you should NEVER fix a computer for free.
    It is in our nature to love the puzzle. We are obsessed. The lot of us. We love puzzles. We love the challenge. We thrive on finding the answer. We hate disarray. It bothers us deep in our soul. W...
  2. SCCM OSD Basic troubleshooting
    SCCM 2007 OSD is a fantastic way to deploy operating systems, however, like most things SCCM issues can sometimes be difficult to resolve due to the sheer volume of logs to sift through and the dispe...
  3. Migrate Small Business Server 2003 to Exchange 2010 and Windows 2008 R2
    This guide is intended to provide step by step instructions on how to migrate from Small Business Server 2003 to Windows 2008 R2 with Exchange 2010. For this migration to work you will need the fo...
  4. Create a Win7 Gadget
    This article shows you how to create a simple "Gadget" -- a sort of mini-application supported by Windows 7 and Vista. Gadgets can be dropped anywhere on the desktop to provide instant information, ...
  5. Outlook continually prompting for username and password
    There have been a lot of questions recently regarding Outlook prompting for a username and password whilst using Exchange 2007. There are a few reasons why this would happen and I will try to cover t...
  6. Backup Exchange 2010 Information Store using Windows Backup
    There seems to be quite a lot of confusion around the ability to backup Exchange 2010 using the built in Windows Backup feature. This stems from the omission of this feature prior to Exchange 2007 s...

Cloud Class Webinars

  1. Avoiding Bugs in Microsoft Access
    Alison Balter takes and in-depth look at avoiding bugs in Access. In this webinar you will learn about using the immediate window to debug your applications, invoking the debugger, using breakpoints to troubleshoot, stepping through code, setting the next statement to execute, ...
  2. Top 10 Best New Features in Visio 2010
    Scott Helmers gives live demonstrations of the top 10 new features in Visio 2010. This webinar will teach you how to create compelling diagrams by adding shapes to the page with a single click, linking the shapes in a diagram to data in Excel (or SQL Server, or SharePoint), ...
  3. IT Consultant Business Secrets Revealed
    Michael Munger, Experts Exchange tech pro and IT consultant, pulls back the curtain on his very successful businesses and answers question on every IT consultant and business owner should know about. He shares secrets on what he did to solve the 5 most common problems in IT, ...
  4. Disaster Recovery and Business Continuity
    Quest CTO, Mike Billon, gives an overview of the steps involved in building a dunamic disaster recovery plan. Through case studies and an examination of software/hardware tooles for monitoring and testing, you'll gain a better understandin of where you are, where you want ...
  5. Organize Your Visio Diagrams with Containers and Lists
    Scott Helmers uses cross functional flowcharts, wireframe diagrams, data graphic legends and seating charts to teach you: how to ustilize all three new structured diagram components in Visio 2010, the best practices for organizeing shapes in previous version of Visio, how to organize ...
  6. How to Us Objects, Properties, Events and Methods in Microsoft Access
    Alison Dalter gives an in-depbth look at objects, properties, events and methods in Microsoft Access. In this webinar you will learn about using the object browser, referring to objects, working with properties and methods, working with object variables, understanding the ...

Join the Community

Give a Little. Get a Lot.

Join the community of experts here and help other tech pros by answering question in your area of expertise. You can earn FREE access to all Experts Exchange's premium features and resources.

Join the Community

Answers

 

by: manav_mathurPosted on 2005-02-03 at 10:18:27ID: 13217302


Firstly,
>print "Shared mem @sharedmem[0]\n";

Should be
print "Shared mem $sharedmem[0]\n";

 

by: jmcgPosted on 2005-02-03 at 10:42:20ID: 13217646

Actually, shouldn't the array be spelled the same way in each place?

print "Shared mem ", $sharemem[0], "\n";

If it weren't for the spelling error (which 'use strict' would have warned about), the construct

print "Shared mem @sharemem[0]\n";

would have worked, even though it works more or less by accident.

 

by: Mike_SiegelPosted on 2005-02-03 at 10:46:38ID: 13217700

Wow, I'm an idiot.  Thanks!

 

by: jmcgPosted on 2005-02-03 at 10:47:05ID: 13217704

Also, for your next assignment, I suggest looking into how the 'for' or 'foreach' construct can be used to avoid explicit manipulation of array indexes.

http://www.perl.com/doc/FMTEYEWTK/style/slide22.html

 

by: manav_mathurPosted on 2005-02-03 at 10:48:39ID: 13217724

I hate B grades.

Manav

 

by: ozoPosted on 2005-02-05 at 06:53:26ID: 13233495

use strict;
#and
use warnings;
#are both useful for catching errors like that.

              $arr3[$n] = ($arr3[$n],$arr1->[$i]);
              $n++;
looks strange.
why are you writng push@arr3,$arr1->[$i]; in such an unusual way?

 

by: bobsedPosted on 2005-02-17 at 08:17:08ID: 13336063

For the record (and I add these notes after the question has been answered so other readers can learn from what's been given and then alternative (hopefully better) techniques), you can do cleaner eliminations/duplicates using hashes.

If you stick your array into a hash -- where each array element is a hash key (set the value to be 1 for simplicity) -- then you instantly remove duplicates from the array. Do this for both arrays and you can then loop through the keys of one hash and see if that key exists in the other hash. If it does that key exists in both hashes, store it.


sub find_dups($$){
  my %hash1 = map { $_=>1 } @{$_[0]};
  my %hash2 = map { $_=>1 } @{$_[1]};
  my @dups;
  for(keys(%hash1)){
    $hash2{$_} && push(@dups, $_);
  }

  return @dups;
}

my @shared = find_dups(\@arr1, \@arr2);

The @{$_[0]} means dereference the array-reference in the first (0th) parameter of the sub routine's parameter list. E.g. convert it back into an array.

The map { $_ => 1 } code is an in-line version of:

my %hash;
for(@array){
 $hash{$_} = 1;
}

It works because map() passes each element of the input array (the above is effectively map({$_ => 1}, @array); ) to the given anonymous sub-routine. Compare it to   sort { $b <=> $a }  for reverse numerical sorting if it helps to see how its used. $_ is set to each element of the array in turn and the output of the anonymous sub-routine (coderef) is stored in $_. Think of it as a pipeline - you put something in, it jiggles it around, and you get something out. The order doesn't change and for every element you put in you get one out, but you can change the contents of the element. In this case we're replacing $_ with $_ => 1 which Perl understands to mean  $_, 1 - I.e. two elements. This means that an input array of, say   a b c d becomes   a, 1, b, 1, c, 1, d, 1.

When you assign an array to a hash variable Perl takes pairs of elements from the array for the key - value. E.g.

 my %hash = qw(a b c d);

Is the same as
 my %hash = (a=>'b', c=>'d');

We want to have our array (a b c d) as the keys though so by inserting the '1's we end up with:

  my %hash = (a=>1, b=>1, c=>1, d=>1);

all in the compact form of   map { $_ => 1}  qw(a b c d);

Note you can also write the first two lines more compactly as:

  my %hash1 = map { $_=>1 } @{+shift};
  my %hash2 = map { $_=>1 } @{+shift};

Assuming your arrayrefs are in the parameter array - you need the + symbol or Perl will see @{shift} as @shift which is a variable which doesn't exist. The + forces it to see it as a function.

The for() loop itself can also be condensed from the above as you want to return the values you find as duplicates:

sub find_dups($$){
  my %hash1 = map { $_=>1 } @{+shift};
  my %hash2 = map { $_=>1 } @{+shift};
  return grep { $_ } map { exists($hash2{$_}) ? $_ : 0} keys(%hash1);
}

This again uses the map() function to alter the value of $_. This time $_ is each element from keys() of %hash1 - E.g. its each key in the list. This time the map is saying if I found $_ (each key from %hash1 in turn) in %hash2 then return $_. Otherwise return 0. This means that you'll get a list like:   a, 0, c, d  (assuming 'b' isn't in array #2). Since this is the array which comes out of map() we need to remove the 0's which is what the grep() function is doing. Its similar to map() and sort() only it will return the element if the return value of the anonymous sub-routine is 1 and nothing otherwise. Effectively we're using it to strip out the 0's and leave just the valid keys. This array is then returned.

You can compact this even more by replacing the map with a more complex grep():

  return grep { $hash2{$_} } keys(%hash1);

$hash2{$_} will return 1 for the key $_ if it exists in %hash2 (because that's its value, you can use exists($hash2{$_}) to just see if it exists irrespective of its value). This means that if it exists grep() will pass through the value that was passed into it (the key to look up) and if it doesn't grep won't return anything.

If you'e looking at this carefully you'll also notice that its wasting resources converting the first array into a hash only to take the keys() of it. Since what you're getting out are the keys you put in you could just avoid the conversion and simply do:

(I've flipped the order so we're now taking the elements of the second array and looking for them in the first)

sub find_dups($$){
  my %hash1 = map { $_=>1 } @{+shift};
  return grep { $hash1{$_} }  @{+shift};
}

Which is much more compact than any of the previous examples (including the one which was accepted).


% perl -Mstrict -Mwarnings
sub find_dups($$){
  my %hash1 = map { $_=>1 } @{+shift};
  return grep { $hash1{$_} }  @{+shift};
}

print join(', ', find_dups([qw(a c d e f g h)], [qw(g f b e)])), "\n";

Gives => g, f, e


NOTE: This will leave duplicates if the exist in the second array. E.g.;

print join(', ', find_dups([qw(a c d e f g h)], [qw(g f b e e)])), "\n";

Gives => g, f, e, e

If you're worried about that, use the two hashes method.

Note also, if you're doing the reverse of this - trying to find elements only in one array - then it becomes more cumbersome again. You can't simply reverse the lookup logic in the grep() because all that tells you is to return elements from array2 not in array1. E.g.
(WRONG EXAMPLE)

sub find_dups($$){
  my %hash1 = map { $_=>1 } @{+shift};
  return grep { !$hash1{$_} }  @{+shift};
}
print join(', ', find_dups([qw(a c d e f g h)], [qw(g f b e e)])), "\n";

Returns 'b'

Doing that you're only halfway there because while you do get the elements in array2 that aren't in array1, you don't get to know what elements exist in array1 which don't exist in array2 (in this case a, c, d, and h). Now since we're already making the comparison to see what is there we know that if we find the element from array2 in array1 (the hash) it exists in both and needs to be removed from both. We know how to ignore those elements (the grep()) from array2 so if we could just remove them from array1 (the hash) what we'd be left with is the elements of array2 which don't appear in the hash, and a hash containing the elements which don't appear in array2. I.e. the elements which don't appear in both arrays.

Fortunately we can do that pretty simply. If the element from array2 exists in the hash we delete it from the hash, because it appears in both places. We can do that using the delete() function. Happily this function returns the value of the key that was deleted so if we remove an element from our hash using delete() we'll get the value of that key - the value 1. E.g.

my %hash = (a=>1, b=>1, c=>1, d=>1);
print delete($hash{a});

Returns '1'

This is great because grep() allows us to filter values based on true/false values. And we know from our 'halfway' point that we can do:

  grep { !$hash1{$_} }

To filter out elements from array2 which DO exist in the hash (which was built from array1). So we can simply replace that with:

  grep { !delete($hash1{$_}) }

And if the element from array2 ($_) exists in the hash then it is deleted *and* it is filtered *out of* the list. This means that when we're finished filtering each elements of array2 through the grep to we have not only removed elements which appear in both lists from array2, but also from the hash. E.g. (the hash has a, b, d, and the array b, c and d, so unique elements are a (in the hash) and c (in array2)

my %hash1 = (a=>1, b=>1, d=>1);
print join(', ',   grep { !delete($hash1{$_}) } qw(b c d)), "\n",
        join(', ', keys(%hash1)), "\n";

Returns:
c
a


Which tells us we have the right information. All we need to do is collect it together and return it:

sub find_uniques($$){
  my %hash1 = map { $_=>1 } @{+shift};
  my @notin2 = grep { !delete($hash1{$_}) }  @{+shift};
  return @notin2, keys(%hash1);
}
print join(', ', find_uniques([qw(a c d e f g h)], [qw(g f b e)])), "\n";

Which returns:
b, h, a, c, d

As expected.

BUT NOTE: Duplicates in the second array screw things up. Take for example the following, with 2 e's:

print join(', ', find_uniques([qw(a c d e f g h)], [qw(g f b e e)])), "\n";

Returns:
b, e, h, a, c, d

Which seems wrong, but is actually right for the code we have. Why? Because on the first 'e' we delete 'e' from the hash. On the second 'e' we find that it doesn't exist in the hash and is therefore "unique" to array2. This is unlikely to be what you want so there are two fixes. You can go back to using two hashes which causes the array passed into the grep() to contain unique elements (because assigning 'e' => 1 to a hash assigns the value of 1 to the key 'e', it doesn't matter how many times you do it, the key is the same (the letter 'e') and so the value is whatever the last value is, since we're always using the same value it removes duplicates in the array - termed "uniquifying" the array):

sub find_uniques($$){
  my %hash1 = map { $_=>1 } @{+shift};
  my %hash2 = map { $_=>1 } @{+shift};
  my @notin2 = grep { !delete($hash1{$_}) } keys(%hash2);
  return @notin2, keys(%hash1);
}
print join(', ', find_uniques([qw(a c d e f g h)], [qw(g f b e e e e)])), "\n";

Which returns b, h, a, c, d as expected.


btw for any newbies reading this don't be like "wow I could never do that". This (hopefully) shows how Perl lets you use a little piece of knowledge and piece it together with other pieces of knowledge to make a better program (a better balance of speed/performance/compactness/readability).

And of course, there is no right way to do it though, as the saying goes. Using multiple hashes may look cleaner, but uses more memory. Deleting from a hash may not save memory and maybe slower because of the operations involved in seeking and rewriting the data (theoretically the program could require more memory to do the delete because it has to mark the old key-value pair as unused and then find enough space for the new key-value pair)

Wow, I really wish I had time to spout all of this stuff before someone else answered the post. I bet it would be worth some points or whatever we get here :) Shame I'm busy doing this for a living really, but hopefully it will help someone searching for an answer to this problem (or maybe just help you understand how things can be improved on - which isn't to say the original versions where bad)

Colin.

20120131-EE-VQP-002

3 Ways to Join

30-Day Free Trial

The Experts

98% positive feedback on 31,087 answers since March 2000. angeliii is a Microsoft Most Valuable Professional for his work with MS SQL Server & Develoment.

He has also proven his knowledge of Visual Basic Programming, PHP Scripting and Oracle Databases.

The Experts

97% positive feedback on 10,752 answers since July 2000. lrmoore has more than 18 years experience in the networking industry.

The six-time Mircosoft MVPs specialties include firewalls, virtual private networking, and network management.

Testimonials

"...and excellent source for support... Kind of like having your very own IT dept." Electriciansnet

Testimonials

"I was apprehensive at signing up at first. However... it has already made my life as an IT administrator much easier." JaCrews

Testimonials

"WOW! You guys have great, active, and knowledgeable people on here." moore50

Business Clients

Business Clients

In the Press

"If you’ve got a question... Experts Exchange can supply an answer.”

In the Press

"...an invaluable aid for both IT professionals and those who require tech support."

In the Press

"where IT professionals provide quick answers on just about any topic"

Business Account Plans

Loading Advertisement...