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

I'm only a Perl beginner and I know there are lots and lots of pages out there that deal with searching through arrays, but I cannot find anything relevant to my problem.

I have two arrays and I want to find if one of the arrays is contained within the other (with the order preserved). Moreover I want to then be able to delete the contents of one array from the other

 @bigarray qw(this is the main array from which to delete elements)

 @smallarray qw(delete elements)

An array such as  @other qw(elements delete) should not match against @bigarray.

I need to somehow remove "delete elements" from @bigarray. I have tried using nested loops, trying to keep track of indexs so I can use splice, but I just can't figure out how to do it properly with loops

@bigarray will probably be <1K in size and this delete action will only be called perhaps once or twice during my script, so efficiency is not an issue.

Any help appreciated :-)

Just for clarity, the exact sequence from @smallarray should be removed from @bigarray i.e.

 @bigarray qw(delete this is elements the main array from which to delete elements)

should be transformed to

 @bigarray qw(delete this is elements the main array from which to)

Thanks!

Replies are listed 'Best First'.
Re: Check if one array is a subset of another
by tobyink (Canon) on Jan 04, 2012 at 17:06 UTC

    Use Set::Scalar.

    use Set::Scalar; my $bigset = Set::Scalar->new(@bigarray); my $smallset = Set::Scalar->new(@smallarray); my $difference = $bigset - $smallset;

    This assumes though that you don't care about array order, and don't care about duplicates - you're treating them as sets.

    Preserving order, and assuming you're on Perl 5.10+, you can just use smart match instead...

    my $smallarray_ref = \@smallarray; my @difference = grep { !($_ ~~ $smallarray_ref) } @bigarray;
      Unfortunately I'm on Perl 5.8, otherwise that solution looks perfect (and simple)! I'm afraid that I will need to preserve the order too.
Re: Check if one array is a subset of another
by BrowserUk (Patriarch) on Jan 04, 2012 at 17:08 UTC

    If, as suggested by your sample code & data, your array elements contain no spaces, then a very simple, and relatively efficient mechanism would be:

    @bigarray = qw(this is the main array from which to delete elements);; @smallarray = qw(delete elements);; ($temp = "@bigarray") =~ s[@smallarray][] and @bigarray = split ' ', +$temp;; print for @bigarray;; this is the main array from which to

    If your elements can contain spaces, then the same technique could be utilised, by using a different separator char -- eg. $;. It is only slightly more complex;

    @bigarray = qw(this is the main array from which to delete elements);; @smallarray = qw(delete elements);; $b = join $;, @bigarray;; $s = join $;, @smallarray;; $b =~ s[$s][] and @bigarray = split $;, $b;; print for @bigarray;; this is the main array from which to

    With the rise and rise of 'Social' network sites: 'Computers are making people easier to use everyday'
    Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
    "Science is about questioning the status quo. Questioning authority".
    In the absence of evidence, opinion is indistinguishable from prejudice.

    The start of some sanity?

Re: Check if one array is a subset of another
by Anonymous Monk on Jan 04, 2012 at 17:18 UTC
    I recognise this to be a typical example of the Longest Common Subsequence problem.
    use Algorithm::Diff qw(LCSidx); my @bigarray = qw(this is the main array from which to delete elements); my @smallarray = qw(delete elements); my ($index_range) = LCSidx \@bigarray, \@smallarray; splice @bigarray, $index_range->[0], @$index_range;
Re: Check if one array is a subset of another
by Khen1950fx (Canon) on Jan 04, 2012 at 17:52 UTC
    Another way to do it:
    #!/usr/bin/perl -l use strict; use warnings; my @big = qw(this is the main array from which to delete elements); my @small = qw(delete elements); my @new = grep { my $x = $_; not grep { $x =~/\Q$_/i } @small } @big; print "@new";
Re: Check if one array is a subset of another
by choroba (Cardinal) on Jan 04, 2012 at 17:00 UTC
      If the big array is a X b c Y d Y e

      and the small array is

       c Y

      then the resulting array would be

      a X b d Y e

      Thanks