<?xml version="1.0" encoding="windows-1252"?>
<node id="527334" title="johngg's scratchpad" created="2006-02-02 09:43:04" updated="2006-02-02 04:43:04">
<type id="182711">
scratchpad</type>
<author id="401112">
johngg</author>
<data>
<field name="doctext">
&lt;code&gt;
# Use strictures and warnings to force declaration of variables and
# catch typos and other errors. This is recommended practice.
#
use strict;
use warnings;

# Use the Data::Dumper standard module to allow us to visualise the
# data structure we have built.
#
use Data::Dumper;

# Initialise the @input array.
#
my @input = qw{
   1200 1300 1200 1000 1100 1200
   1500 1700 2000 2100 3000 2100
   1200 1500 1700 1700
   };

# Assign our groups of unique items to the @groups array; the groups
# are returned as a list of references to arrays by the deDup
# subroutine which is called with a reference to the @input array as
# a parameter.
#
my @groups = deDup( \ @input );

# Print the Data::Dumper representation of our resultant @groups
# array.
#
print Data::Dumper-&gt;Dumpxs( [ \ @groups ], [ qw{ *groups } ] );

# Declare the deDup subroutine.
#
sub deDup
{
    # Assign the reference to an array passed as the sole argument
    # to the $raToCheck scalar variable.
    #
    my $raToCheck = shift;

    # Initialise two array references (also known as anonymous arrays)
    # that will hold our unique items and our duplicates. Also declare
    # a hash %seen that we will use to find our duplicates.
    #
    my $raUniq = [];
    my $raDups = [];
    my %seen;

    # This is where we find duplicates. We use @$raToCheck to de-
    # reference the array reference held in the $raToCheck scalar in
    # order to access each element. Each element is passed in turn in
    # the $_ scalar variable by the "for" statement modifier to the
    # code to its left. That code pushes the item onto one of two
    # anonymous arrays depending on whether that item has already
    # been seen or not. If the item has not been seen there will not
    # yet be an element in the %seen hash with a key matching that
    # item so the test $seen{ $_ } ++ ? will be false, the item will
    # be pushed onto @$raUniq then the ++ post-increment will ensure
    # that $seen{ $_ } has a value of 1 so that, if that item is
    # encountered again, the test will now be true and the item will
    # be pushed onto @$raDups;
    #
    push @{ $seen{ $_ } ++ ? $raDups : $raUniq }, $_ for @$raToCheck;

    # This is where the recursion happens. The subroutine returns the
    # reference to the array of unique values and, if the anonymous
    # array of duplicates is not empty, it calls itself with the
    # duplicates as an argument, otherwise an empty list. So the
    # returmed list is of a successively smaller series of anonymous
    # arrays until there are no duplicates to be found.
    # 
    return $raUniq, @$raDups ? deDup( $raDups ) : ();
}
&lt;/code&gt;</field>
</data>
</node>
