Recipe 4.7. Finding Elements in One Array but Not Another
Author: Tom Christiansen & Nathan Torkington
Date: 1999-07-02T01:31:34Z

#

| Chapter 4 Arrays |

## 4.7. Finding Elements in One Array but Not Another

### Problem

You want to find elements that are in one array but not another.

### Solution

You want to find elements in `@A` that aren't in `@B`. Build a hash of the keys of `@B` to use as a lookup table. Then check each element in `@A` to see if it is in `@B`.

#### Straightforward implementation

    # assume @A and @B are already loaded
    %seen = ();                  # lookup table to test membership of B
    @aonly = ();                 # answer

    # build lookup table
    foreach $item (@B) { $seen{$item} = 1 }

    # find only elements in @A and not in @B
    foreach $item (@A) {
        unless ($seen{$item}) {
            # it's not in %seen, so add to @aonly
            push(@aonly, $item);
        }
    }

#### More idiomatic version

    my %seen; # lookup table
    my @aonly;# answer

    # build lookup table
    @seen{@B} = ();

    foreach $item (@A) {
        push(@aonly, $item) unless exists $seen{$item};
    }

### Discussion

As with nearly any problem in Perl that asks whether a scalar is in one list or another, this one uses a hash. First, process `@B` so that the `%seen` hash records each element from `@B` by setting its value to 1. Then process `@A` one element at a time, checking whether that particular element had been in `@B` by consulting the `%seen` hash.

The given code retains duplicate elements in `@A` . This can be easily fixed by adding the elements of `@A` to `%seen` as they are processed:

    foreach $item (@A) {
        push(@aonly, $item) unless $seen{$item};
        $seen{$item} = 1;                       # mark as seen
    }

The two solutions differ mainly in how they build the hash. The first iterates through `@B`. The second uses a hash slice to initialize the hash. A hash slice is easiest illustrated by example:

    $hash{"key1"} = 1;
    $hash{"key2"} = 2;

is equivalent to:

    @hash{"key1", "key2"} = (1,2);

The list in the curly braces holds the keys; the list on the right holds the values. We initialize `%seen` in the first solution by looping over each element in `@B` and setting the appropriate value of `%seen` to 1. In the second, we simply say:

    @seen{@B} = ();

This uses items in `@B` as keys for `%seen`, setting each corresponding value to `undef`, because there are fewer values on the right than places to put them. This works out here because we check for existence of the key, not logical truth or `defined`ness of the value. If we needed true values, a slice could still shorten our code:

    @seen{@B} = (1) x @B;

### See Also

Hash slices are explained in perldata (1) and the "Variables" section of Chapter 2 of Programming Perl; Chapter 5; we use hashes in a similar fashion in Recipe 4.6 and Recipe 4.8

4.6. Extracting Unique Elements from a List |  | 4.8. Computing Union, Intersection, or Difference of Unique Lists