NAME
    Set::ArrayAlt - arrays as objects with list/set operations

SYNOPSIS
       $obj = new Set::ArrayAlt [@list];

DESCRIPTION
    This module attempts to provide a complete set of set and list
    operations. It acts as a standalone module, or is available in
    Template::Toolkit templates using the companion module
    Template::Plugin::ListOps .

    It performs many of the same functions as the Set::Array module, but has
    better support for handling duplicate elements in lists, and does not
    require the Want module. For more details, please refer to the HISTORY
    AND RATIONALE section below.

BASE OBJECT METHODS
    new
           $obj = new Set::EndArray [@list];

        This creates a new Set::EndArray object. If @list is passed in, this
        is set to the initial set of elements.

    version
           $vers = $obj->version();

        Gets the version of this module.

    err
    errmsg
           $err = $obj->err();

        Check to see if the previous operation produced an error.

           $msg = $obj->errmsg();

        If an operation did produce an error, this will get the error
        message.

LIST EXAMINATION METHODS
    The following methods examine a list but do not modify the object. They
    will all produce an error if the list has not been defined and undef is
    returned.

    as_hash
           %hash = $obj->as_hash();

        This returns a hash that describes the list contained in $obj. Every
        defined value in the list is one of the keys in %hash. The value of
        %hash is the number of times that element appears in the list.

    at
           $ele = $obj->at($n);

        This returns the element at position $n in the list (position
        numbering starts at 0). Negative numbers can also be used to count
        from the end.

           @ele = $obj->at(@n);

        This returns the elements at the given positions. This will return
        an error in scalar context (if @n contains more than one index).

    count
           $num = $obj->count([$val]);

        This counts the number of times val appears in the list. If $val is
        not given, it counts the number of undef elements in the list.

    exists
           $flag = $obj->exists([$val]);

        This returns 1 if the value $val exists in the list. If $val is not
        passed in, it tests for undef values.

        If $val does not exist, it returns 0.

    first
    last
           $val = $obj->first();
           $val = $obj->last();

        These return the first or last elements of the list.

    index
    rindex
           $idx = $obj->index([$val]);
           @idx = $obj->index([$val]);

           $idx = $obj->rindex([$val]);
           @idx = $obj->rindex([$val]);

        In list context, these return the index of every occurrence of $val
        in the list. If $val is not passed in, the indices of all undef
        elements are returned.

        The rindex function returns them in reverse order.

        In scalar context, the index and rindex methods return the index of
        the first or last occurrence of $val in the list.

    is_empty
           $flag = $obj->is_empty([$undef]);

        This checks to see if the list is empty. If $undef is not passed in,
        a list is empty only if the length is 0.

        If $undef is passed in, the list is also empty if it consists only
        of undef values.

    length
           $num = $obj->length();

        Returns the number of elements in the list.

    list
           @list = $obj->list();

        This returns the list stored in the object.

SIMPLE LIST MODIFICATION METHODS
    The following methods will modify the object.

    They will all produce an error if the list has not been defined and
    undef is returned.

    clear
           $obj->clear();

        This removes all elements from the list (sets it to a zero-length
        list).

           $obj->clear(1);

        This sets all elements in the list to be undef (preserving the
        length). The list must be defined or an error results.

    compact
           $obj->compact();

        This removes any undef objects from the list.

    delete
           $obj->delete($all,$undef,@val);

        This deletes occurences of each values from the list.

        If $all is 1, all occurences are removed. Otherwise, only the first
        occurence of each value is removed.

        If $undef is 1, values are replaced with undef. Otherwise, they are
        completely removed.

    delete_at
           $obj->delete($undef,@idx);

        This deletes elements at the given indices. The order of the indices
        is not important. They will be deleted in the order of last to
        first.

        If $undef is 1, values are replaced with undef. Otherwise, they are
        completely removed.

    fill
           $obj->fill([$val,] [$start,] [$length]);

        This sets elements of a list to be $val. If $val is not passed in,
        values are set to undef.

        $start can be a positive or negative number. It must be an index in
        the list. It can also be the index of the first element after the
        list. So, if the list contains 3 elements, $start can be -3 to +3.
        Negative values refer to the index from the end as usual. 0 to 2
        refer to the index of the elements in the list, and 3 is the first
        element after the list. $start defaults to 0.

        $length can be any positive value and refers to the number of
        elements that will be set to the value. If $length is omitted, it
        defaults to the number of elements in the list starting at $start,
        or to 1 if $start is the first element after the list.

        So if list contains 3 elements, and $start is 1, $length will
        default to 2 (the number of elements in the list starting at index
        1.

    list
           $obj->list(@list);

        This sets the object to contain the given list. Any previous list is
        replaced.

    min
    max
           $ele = $obj->min([$method [,@args]]);
           $ele = $obj->max([$method [,@args]]);

        These return the first/last value from the list if it were sorted
        with the given method using the Sort::DataTypes module.

        By default, if $method is not given, the numerical minimum/maximum
        value is given.

        Otherwise, $method can be any sort method available from the
        Sort::DataTypes module.

        For example, to get the first word alphabetically, use

           $ele = $obj->min("alphabetic");

    pop
    shift
           $val = $obj->pop();

           $val = $obj->shift();

        These perform the standard pop/shift operations.

    push
    unshift
           $obj->push(@list);

           $obj->unshift(@list);

        These perform the standard push/unshift operations.

    randomize
           $obj->randomize();

        This randomly shuffles the list.

    reverse
           $obj->reverse();

        This reverses the list.

    rotate
           $obj->rotate([$num]);

        This rotates the list.

        If $num is not included, it defaults to 1.

        If $num is a positive number, the first element from the list is
        removed and pushed on to the end a total of $num times.

        If $num is a negative number, the last element from the list is
        removed and shifted onto the front a total of $num times.

    set
           $obj->set($index [,$val]);

        This sets the list index to the given value, or undef if no value is
        passedin.

    sort
           $obj->sort([$method [,@args]]);

        This uses any method from the Sort::DataTypes module to sort the
        list.

        Method can be of the form "numerical" or "rev_numerical" to do
        forward and reverse sorting.

        @args may be passed in if the method requires additional arguments.

        If no method is given, it defaults to alphabetical sorting.

    splice
           @vals = $obj->splice([$start,] [$length,] [@list]);

        This performs the perl splice command on a list.

        If $start is omitted (or is undefined), it defaults to 0. If $length
        is omitted (or undefined), it defaults to the end of the list.

        The values removed are returned, and are replaced with @list if
        present.

    unique
           $obj->unique();

        This removes any duplicates in a list. The first occurrence of each
        element is kept, and the order of those first occurrences is
        preserved.

SET METHODS
    The following methods work with two Set::ArrayAlt objects. They apply a
    set operation to the two of them and produce a value or a third
    Set::ArrayAlt object containing the results.

    If an error occurs, it is set in the returned object, NOT in any of the
    original objects.

    The original objects are unmodified in all cases.

    difference
           $obj3 = $obj->difference($obj2 [,$unique]);

        This takes two lists and removes the second list from the first.

        By default, one occurence of every element in the second list is
        removed from the first list.

        If $unique is given, every element in the first list is removed.

        For example, the difference of the two lists (a a b b c) and (a) is
        either (a b b c) or (b b c). If $unique is non-zero, the second is
        given.

        It should be noted that both "b" elements in the example will be
        kept regardless of the value of $unique because the $unique flag
        only affects elements being removed.

    intersection
           $obj3 = $obj->intersection($obj2 [,$unique]);

        This takes two lists and finds the intersection of the two. The
        intersection are elements that are in both lists. The returned list
        is in the order they appear in the first list.

        By default, duplicate elements are treated individually unless
        $unique is passed in.

        For example, the intersection of two lists (a a b b c) and (a a c d)
        is either (a a c) or (a c). If $unique is non-zero, the second is
        given.

    is_equal
    not_equal
           $flag = $obj->is_equal($obj2 [,$unique]);
           $flag = $obj->not_equal($obj2 [,$unique]);

        These take two lists and test to see if they are equal. If an error
        is encountered, undef is returned, but no error is stored.

        The order of the elements is ignored so (a,b) = (b,a).

        If $unique is non-zero, the count of each type of element is ignored
        so (a,a,b) = (a,b). Otherwise, the count is important so (a,a,b) !=
        (a,b).

    symmetric_difference
           $obj3 = $obj->symmetric_difference($obj2 [,$unique]);

        This takes two lists and finds the symmetric difference of the two.
        The symmetric difference are elements that are in either list, but
        not both. The order of the list produced are the elements from the
        first object (order preserved) followed by those from the second
        object.

        If $unique is non-zero, one instance of an element cancels out all
        of the instances in the other list.

        For example, the symmetric difference between the two lists (a a b b
        c) and (a c) is either (a b b) or (b b). If $unique is non-zero, the
        second is used.

    union
           $obj3 = $obj->union($obj2 [,$unique]);

        This takes two lists and combines them.

        By default, every element is preserved. If $unique is passed in, the
        duplicates are removed.

        For example, the union of the two lists (a a b) and (a c) is either
        (a a b a c) or (a b c). The second is returned if $unique is
        non-zero.

HISTORY AND RATIONALE
    With several other modules out there that do various set and list
    operations, a brief history of why I wrote this module is in order.

    The origin of this module came when I needed better list handling
    operations (especially involving lists that might contain duplicate
    elements) inside of a Template::Toolkit template. The built in list
    functions in Template::Toolkit weren't sufficent for my needs, so I
    looked around.

    The module that came closest to my needs was Set::Array. Although not a
    perfect match for what I wanted (I really wanted better support for
    lists with duplicate elements), it came close enough, so I wrote a
    wrapper module (Template::Plugin::ListOps) around it to do most of what
    I wanted.

    Unfortunately, I discovered almost immediately that Set::Array suffered
    from a fairly serious problem. It depends on the Want module which had
    some known problems and would fail under some circumstances (older
    versions of perl if I recall correctly, though I could be wrong about
    that), and unfortunately, some of the places I needed my module to run
    failed due to those problems.

    I looked at the Want module, but correcting it was beyond my abiltity,
    so the best solution seemed to be to rewrite the module without
    depending on Set::Array. This would also allow me to add the
    functionality that I wanted.

    So I did that. I rewrote each function to do the list/set operation I
    wanted instead of call Set::Array functions.

    Almost as soon as I was done (and perhaps even before), I started
    regretting rewriting the module in that way. I should have written a
    standalone module and then had the Template::Plugin::ListOps be a
    wrapper for it instead of Set::Array... but in the interest of time, I
    didn't go back and redo it.

    Until now.

    I recently ran into a case where I wanted the set/list functionality
    from Template::Plugin::ListOps for another application.

    So, this module takes the routines from Template::Plugin::ListOps and
    moves them into a standalone module. Template::Plugin::ListOps will be
    rewritten to be a wrapper around this module.

    Some other notes:

    Since the original version of Template::Plugin::ListOps (which was never
    released) was a wrapper around Set::Array, the naming of the functions
    is very similar, but the functionality differs slightly.

    This module is named Set::ArrayAlt to indicate that it is based on
    Set::Array, but with a few changes. It has enhanced functionality with
    respect to duplicate elements but is missing some of the functionality
    of Set::Array (especially method chaining and operator overloading)
    which depend on the Want module. This module is not intended to be a
    drop-in replacement for Set::Array.

    It may be that the problems with the Want module have been corrected at
    this point, and that I could have used Set::Array, but since some of the
    functionality I needed was the enhanced duplicate element handling, and
    since creating this module from what I'd already written was actually a
    pretty easy task, I decided to go ahead with the creation of this
    module.

    Anyway, that's the history. Hopefully, I'm justified in reinventing the
    wheel.

KNOWN PROBLEMS
    None at this point.

LICENSE
    This script is free software; you can redistribute it and/or modify it
    under the same terms as Perl itself.

AUTHOR
    Sullivan Beck (sbeck@cpan.org)

