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

Hello , Here is a code that is supposed to generate union of two array. The error with this code is that, the generated array contains redundent info which is not desired . Kindly identify the error and suggest solution.. Thanks in advance..
my @arr_in_1 =("User1","user2","user3"); my @arr_in_2 =("user2","user3","User4"); my @union_arr; foreach my $arr_1(@arr_in_1) {push(@union_arr,$arr_1);} foreach my $arr_1(@arr_in_1) { #print "The value in array 1 is :" .lc $arr_1."\n"; foreach my $arr_2(@arr_in_2) { #print "the value in array 2 is :". lc $arr_2." \n"; if (lc $arr_2 ne lc $arr_1) { push(@union_arr,$arr_2); } } } print "union array @union_arr";

Edit kudra, 2002-10-27 Added code tags

Anandatirtha

Replies are listed 'Best First'.
Re: Union of arrays
by Zaxo (Archbishop) on Oct 26, 2002 at 08:29 UTC

    You already have correct answers. I like to do it like this:

    my (%hsh, @union_arr); @hsh{@arr_in_1, @arr_in_2} = (); @union_arr = keys %hsh;

    After Compline,
    Zaxo

      The hash slice is very neat, but you're going to lose sequence that way, which might matter. How about a nearly-one-liner:

      my %seen; my @union = grep { not $seen{$_}++ } (@arr_in_1, @arr_in_2);

      which also skips duplicates in the existing arrays, as yours would.

      Btw, does the hash slice - if, indeed, that's what it is - cut out this loop altogether, or does it just conceal it? If the former then I imagine this approach is a lot less efficient.

      ananda: the perl cookbook deals with this kind of question very well, iirc.

      update: code tweak

Re: Union of arrays
by blokhead (Monsignor) on Oct 26, 2002 at 07:57 UTC
    You probably want to use a hash to keep track of previously seen elements, instead of using nested for loops. Also there are a few other simplifications you could make, such as
    # replacing my @union_arr; foreach my $arr_1(@arr_in_1) {push(@union_arr,$arr_1);} # with this: my @union_arr = @arr_in_1;
    I would also imagine that taking a look at the internals of a module like Set::Array, or one of the other many Set:: modules that include a union function, might prove insightful. You also may want to check out this recent node, which is a discussion on set membership, but there are some other general-purpose set-related CPAN modules mentioned.

    blokhead

Re: Union of arrays
by Enlil (Parson) on Oct 26, 2002 at 07:50 UTC
    I am going to assume the code was meant to look like so until you fix your code tags.

    my @arr_in_1 =("User1","user2","user3"); my @arr_in_2 =("user2","user3","User4"); my @union_arr; foreach my $arr_1(@arr_in_1) { push(@union_arr,$arr_1); } foreach my $arr_1(@arr_in_1) { #print "The value in array 1 is :" .lc $arr_1."\n"; foreach my $arr_2(@arr_in_2) { #print "the value in array 2 is :". lc $arr_2." \n"; if (lc $arr_2 ne lc $arr_1) { push(@union_arr,$arr_2); } } } print "union array @union_arr";
    The main problem is the statement lc $arr_2 ne lc $arr_1 which will always result in truth (in this case). For instance think about what is being compared.

    first loop(first element in @arr_in_1) vs inner loop(@arr_in_2):
    user1 ne user2 (true)
    user1 ne user3 (true)
    user1 ne user4 (true)
    so obviously this is inserted into the union array.

    second loop:
    user2 ne user2 (false)
    user2 ne user3 (true) Again pushed into the union array
    ...

    Well you get my drift. Your on the right track just have to make a couple modifications.

    -enlil

Re: Union of arrays
by hopes (Friar) on Oct 27, 2002 at 03:55 UTC
    Just one comment more.
    In perlfaq4 you have a chunk of code to evaluate union, intersection a difference from two arrays.
    "How do I compute the difference of two arrays? How do I compute the intersection of two arrays?"
    You can see question/answer here
    perldoc -q intersection

    Hopes
    perl -le '$_=$,=q,\,@4O,,s,^$,$\,,s,s,^,b9,s,$_^=q,$\^-]!,,print'
Re: Union of arrays
by Ananda (Pilgrim) on Oct 26, 2002 at 11:35 UTC
    Hello , I have been able to overcome the problem by modifying the inner loop. Thanks for all the suggestions made so far. I solicit more coments, views and solutions on this topic. Greetings!!!!!. Anandatirtha
      Even so, you should use thpfft's suggestion, as it's a more efficient algorithm.

      Makeshifts last the longest.