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

I need to compare two arrays. @array1 has a list of elements I already have. @array2 has another long list of elements. i need to make @array3 that has both the elements of @array1 and @array2. I am using a push statements, but there are some similar elements in both @array1 & @array2 so they appear twice in @array3. How can I get make them appear only once? Please help?

Replies are listed 'Best First'.
Re: Arrays
by dragonchild (Archbishop) on Dec 08, 2001 at 00:42 UTC
    Use an intermediate hash, like thus:
    my %intermediateHash; $intermediateHash{$_}++ for (@array1, @array2); my @array3 = keys %intermediateHash;

    ------
    We are the carpenters and bricklayers of the Information Age.

    Don't go borrowing trouble. For programmers, this means Worry only about what you need to implement.

Re: Arrays
by runrig (Abbot) on Dec 08, 2001 at 00:50 UTC
    Yet another (non-iterative) variation on the same (hash) theme:
    my @union = do { my %hash; @hash{@array1,@array2}=(); keys %hash };
      Hey, that's very cool! This is starting to look like
      a golf match. Let me use your method to remove the
      foreach() loop from my solution:
      my %hash = (); @hash{ @array1, @array2 } = (); @array3 = keys %hash;

      I say once again: This is very cool!

      Rob

        ... or even:
        @array3 = keys %{{ map {$_ =>1} @array1, @array2 }};
        - danboo
        Let me explain this (I've noticed that non-iterative
        solutions are often odd-looking because they have no
        cognate in the non-perl world):
        my %hash = ();
        This just creates a new, empty, associative array.
        @hash{ @array1, @array2 } = ();
        In this single line, the associative array has effectively
        removed the duplicates from @array1 and @array2 for free.

        This is a list assignment; that is, this single line
        assigns into multiple keys. Just as $hash{$foo} = 0
        creates a string key from $foo in the hash %hash,
        so @hash{ @array } creates a bunch of keys, whose
        members are named in @array, in the hash %hash. Also,
        since two arrays mashed together form one big array--
        that is, (@a1,@a2,@a3) becomes one flat array-- so then
        the assignment @hash{ @array1, @array2 } creates string
        keys out of each element in the arrays for %hash.
        Since we know that keys are by nature unique, the
        hashtable has removed the duplicates for us, for free!
        So, now all there is left to do is extract the keys
        from the hashtable:

        @array3 = keys %hash;

        ...and we're done.

        Rob

        Let's establish some ground rules.

        Provide a function that takes two arrayrefs, combines them and returns an array containing all the elements in the previous two arrays, bu no duplicates.

        As I don't know them, you can't use commandline opts. *grins*

        my @arr1 = (1, 2, 3, 4, 5); my @arr2 = (4, 5, 6, 7, 8); my @arr3 = f(\@arr1, \@arr2); sub f { #234567890#234567890#234567890 @h{map{@$_}@_}=1;keys%h }
        23 characters, and I know I can do better.

        Update: 22 chars

        @h{map@$_,@_}=1;keys%h

        ------
        We are the carpenters and bricklayers of the Information Age.

        Don't go borrowing trouble. For programmers, this means Worry only about what you need to implement.

Re: Arrays
by joealba (Hermit) on Dec 08, 2001 at 00:43 UTC
    my @array1 = (1, 2, 3); my @array2 = (3, 4, 5); my %union = (); map { $union{$_}++ } (@array1, @array2); my @array3 = keys %union;
    Update: dragonchild is right. map is slower than a for loop. Use his code above, but you should still learn the wonderful world of map!

    Update2:I like this one by danboo the best: @array3 = keys %{{ map {$_ =>1} @array1, @array2 }}; It uses map in a non-void context, does a simple assignment operation instead of the addition/auto-vivify, and is still quite readable. Am I wrong? Is there a more optimized solution?
      Just to nitpick - using map in a void context is generally considered poor style. It's also slower than the corresponding for loop. (And, almost always, less characters, closer to English, and uses "less complex" syntax.) *shrugs*

      ------
      We are the carpenters and bricklayers of the Information Age.

      Don't go borrowing trouble. For programmers, this means Worry only about what you need to implement.

        Yeah, well, map pays me a monthly fee to use it everywhere possible. It's a whole marketing campaign. Soon you'll see got map? stickers on ThinkGeek.com and banner ads on PerlMonks and Slashdot - "First map!".

        Sorry.. :) I'm just a map fan.
      Ah, you used map(). I'm going to have to learn that
      function and start using it.

      Rob

Re: Arrays
by mpeppler (Vicar) on Dec 08, 2001 at 00:48 UTC
    You could use something like this:
    my @a1 = qw(one two three); my @a2 = qw(one five four); my %h = map { $_ => 1 } (@a1, @a2); my @r = keys(%h); print "@r\n";
    This uses the map operator to create a hash, and then we extract the keys from this hash to an array.
    There are no doubt other ways to do this - but this one's fairly straightforward.

    Michael

Re: Arrays
by rje (Deacon) on Dec 08, 2001 at 00:45 UTC
    You could use a hashtable:
    my %hashOfAllElements = (); foreach $element (@array1, @array2) { $hashOfAllElements{ $element }++; } my @array3 = keys %hashOfAllElements;
    I think that might do what you want.

    Rob

Re: Comparing Two Arrays
by davorg (Chancellor) on Dec 10, 2001 at 14:02 UTC

    The problem with all the hash-based solutions is that they lose the ordering of the arrays. If the order is important, then try this:

    foreach (@array1, @array2) { push(@array3, $_) unless $seen{$_}++; }
    --
    <http://www.dave.org.uk>

    "The first rule of Perl club is you do not talk about Perl club."
    -- Chip Salzenberg

A reply falls below the community's threshold of quality. You may see it by logging in.
A reply falls below the community's threshold of quality. You may see it by logging in.