The Collection Classes

A collection is an object that contains a number of items, which can be any objects. Every item stored in a Rexx collection has an associated index that you can use to retrieve the item from the collection with the AT or [] methods.

Each collection defines its own acceptable index types. Rexx provides the following collection classes:

Array

A sequenced collection of objects ordered by whole-number indexes.

Bag

A collection where the index and the item are the same object. Bag indexes can be any object and each index can appear more than once.

CircularQueue

The CircularQueue class allows for storing objects in a circular queue of a predefined size. Once the end of the queue has been reached, new item objects are inserted from the beginning, replacing earlier entries. The collected objects can be processed in FIFO (first in, first out) or in a stack-like LIFO (last in, first out) order.

Directory

A collection with character string indexes. Index comparisons are performed using the string == comparison method.

List

A sequenced collection that lets you add new items at any position in the sequence. A list generates and returns an index value for each item placed in the list. The returned index remains valid until the item is removed from the list.

Properties

A collection with character string indexes and values. Properties collections include support for saving and loading from disk files.

Queue

A sequenced collection with the items ordered as a queue. You can remove items from the head of the queue and add items at either its tail or its head. Queues index the items with whole-number indexes, in the order in which the items would be removed. The current head of the queue has index 1, the item after the head item has index 2, up to the number of items in the queue.

Relation

A collection with indexes that can be any object. A relation can contain duplicate indexes.

Set

A collection where the index and the item are the same object. Set indexes can be any object and each index is unique.

Stem

A collection with character string indexes constructed from one or more string segments. Index comparisons are performed using the string == comparison method.

Table

A collection with indexes that can be any object. A table contains no duplicate indexes.

IdentityTable

A collection with indexes that can be any object. The IdentityTable class determines index item matches by using an object identity comparison. With object identity matches, an index will only match the same object instance. An identity table contains no duplicate indexes.

Organization of the Collection Classes

The following shows the logical organization of the Collection Classes. This does NOT represent the order that methods are inherited but rather the organization of the classes.

Collection
   MapCollection
      Directory
      Properties
      Relation
      Stem
      Table
      IdentityTable
   OrderedCollection
      Array
      List
      Queue
      CircularQueue
   SetCollection
      Bag
      Set

The Collection Class

The Collection class is a MIXIN class that defines the basic set of methods implemented by all Collections. Many of the Collection class methods are abstract and must be implemented the inheriting subclasses.

Figure 5-12. The Collection Class

[]

     +-,-----+
     V       |
>>-[---index-+-]-----------------------------------------------><

Returns the item associated with the specified index or indexes. If the collection has no item associated with the specified index or indexes, this method returns the Nil object. This is an abstract method that must be implemented by a subclasses.

[]=

     +-,-----+
     V       |
>>-[---index-+-]=value-----------------------------------------><

Add an item to the collection at the specified index. This is an abstract method that must be implemented by a subclasses.

allIndexes

>>-allIndexes--------------------------------------------------><

Return an array of all indexes used by this collection. This is an abstract method that must be implemented by a subclasses.

allItems

>>-allItems----------------------------------------------------><

Return an array containing all items stored in the collection. This is an abstract method that must be implemented by a subclasses.

at

       +-,-----+
       V       |
>>-at(---index-+-)---------------------------------------------><

Returns the item associated with the specified index or indexes. If the collection has no item associated with the specified index or indexes, this method returns the Nil object. This is an abstract method that must be implemented by a subclasses.

difference

>>-difference(argument)----------------------------------------><

Returns a new collection (of the same class as the receiver) containing only those items from the receiver whose indexes the argument collection does not contain. The argument can be any collection class object. The argument must also allow all of the index values in the receiver collection.

hasIndex

             +-,-----+
             V       |
>>-hasIndex(---index-+-)---------------------------------------><

Returns 1 (true) if the array contains an item associated with the specified index or indexes. Returns 0 (false) otherwise.

hasItem

>>-hasItem(item)-----------------------------------------------><

Returns 1 (true) if the collection contains the specified item at any index location. Returns 0 (false) otherwise.

index

>>-index(item)-------------------------------------------------><

Return the index associated with item. If item occurs more than once in the collection, the returned index value is undetermined. This is an abstract method which must be implemented by a subclass of this class.

intersection

>>-intersection(argument)--------------------------------------><

Returns a new collection (of the same class as the receiver) containing only those items from the receiver whose indexes are in both the receiver collection and the argument collection. The argument can be any collection class object. The argument must also allow all of the index values in the receiver collection.

items

>>-items-------------------------------------------------------><

Returns the number of items in the collection.

makeArray

>>-makeArray---------------------------------------------------><

Returns a single-index array with the same number of items as the receiver object. Any index with no associated item is omitted from the new array. Items in the new array will have the same order as the source array.

put

            +--------+
            V        |
>>-put(item---,index-+-)---------------------------------------><

Add an item to the collection at the specified index. This is an abstract method that must be implemented by a subclass if this class.

subset

>>-subset(argument)--------------------------------------------><

Returns 1 (true) if all indexes in the receiver collection are also contained in the argument collection; returns 0 (false) otherwise. The argument can be any collection class object. The argument must also allow all of the index values in the receiver collection.

supplier

>>-supplier----------------------------------------------------><

Returns a Supplier object for the collection. The supplier allows you to enumerate through the index/item pairs for the collection. The supplier is created from a snapshot of the collection and is unaffected by subsequent changes to the collection's contents.

union

>>-union(argument)---------------------------------------------><

Returns a new collection of the same class as the receiver that contains all the items from the receiver collection and selected items from the argument collection. This method includes an item from argument in the new collection only if there is no item with the same associated index in the receiver collection and the method has not already included an item with the same index. The order in which this method selects items in argument is unspecified (the program should not rely on any order.). The argument can be any collection class object. The argument must also allow all of the index values in the receiver collection.

xor

>>-xor(argument)-----------------------------------------------><

Returns a new collection of the same class as the receiver that contains all items from the receiver collection and the argument collection; all indexes that appear in both collections are removed. The argument can be any collection class object. The argument must also allow all of the index values in the receiver collection.

The MapCollection Class

The MapCollection class is a MIXIN class that defines the basic set of methods implemented by all collections that use create a mapping from an index object to a value.

Figure 5-13. The MapCollection class

This class is defined as a mixin class.

putAll

>>-putAll(collection)------------------------------------------><

Adds all items collection to the target directory. The collection argument can be any object that supports a supplier method. Items from collection are added using the index values returned by the supplier. The item indexes from the source collection must be strings. The items are added in the order provided by the supplier object. If duplicate indexes exist in collection, the last item provided by the supplier will overwrite previous items with the same index.

makeArray

>>-makeArray---------------------------------------------------><

Returns a single-index array of the index values used by the receiver object. The index objects will not be ordered in any predictable order.

The OrderedCollection Class

The OrderedCollection class is a MIXIN class that defines the basic set of methods implemented by all collections that have an inherent index ordering, such as an array or a list.

Figure 5-14. The OrderedCollection class

This class is defined as a mixin class.

append

>>-append(item)------------------------------------------------><

Append an item to the end of the collection ordering. This is an abstract method that must be implemented by a subclass if this class.

appendAll

>>-appendAll(collection)---------------------------------------><

Appends all items in collection to the end of the target collection. The collection may be any object that implements an allItems() method.

difference

>>-difference(argument)----------------------------------------><

Returns a new collection (of the same class as the receiver) containing only those items from the receiver that are not also contained in the argument collection. The argument can be any collection class object.

intersection

>>-intersection(argument)--------------------------------------><

Returns a new collection (of the same class as the receiver) containing only those items from the receiver that are in both the receiver collection and the argument collection. The argument can be any collection class object.

subset

>>-subset(argument)--------------------------------------------><

Returns 1 (true) if all items in the receiver collection are also contained in the argument collection; returns 0 (false) otherwise. The argument can be any collection class object.

union

>>-union(argument)---------------------------------------------><

Returns a new collection of the same class as the receiver that contains all the items from the receiver collection and selected items from the argument collection. This method includes an item from argument in the new collection only if there is no equivalent item in the receiver collection and the method has not already included. The order in which this method selects items in argument is unspecified (the program should not rely on any order.). The argument can be any collection class object.

xor

>>-xor(argument)-----------------------------------------------><

Returns a new collection of the same class as the receiver that contains all items from the receiver collection and the argument collection; all items that appear in both collections are removed. The argument can be any collection class object.

The SetCollection Class

This is a tagging mixin class only and does not define any methods of its own. Collections that implement SetCollection are MapCollections that constrain the index and item to be be the same object.

Figure 5-15. The SetCollection class

This class is defined as a mixin class.

The Array Class

An array is a possibly sparse collection with indexes that are positive whole numbers. You can reference array items by using one or more indexes. The number of indexes is the same as the number of dimensions of the array. This number is called the dimensionality of the array.

Array items can be any valid Rexx object. If an object has not been assigned to an array index then that index is considered to contain the NIL object.

Figure 5-16. The Array class and methods

Note: The Array class also has available class methods that its metaclass, the Class class, defines. It also inherits methods from the Ordered Collection class.

Array objects are variable-sized. The dimensionality of an array is fixed, but the size of each dimension is variable. When you create an array, you can specify a hint about how many elements you expect to put into the array or the array's dimensionality. However, you do not need to specify a size or dimensionality of an array when you are creating it. You can use any whole-number indexes to reference items in an array.

For any array method that takes an index, the index may be specified as either individual arguments or as an array of indexes. For example, the following are equivalent:

    x = myarray[1,2,3]   -- retrieves an item from a multi-dimension array
    index = .array~of(1,2,3)  -- create an index list
    x = myarray[index]   -- also retrieves from "1,2,3"

Methods such as index() that return index items will return a single numeric value for single-dimension arrays and an array of indexes for multi-dimension arrays.

new (Class Method)

>>-new-+----------------+--------------------------------------><
       |    +-,----+    |
       |    V      |    |
       +-(----size-+--)-+

Returns a new empty array. If you specify any size arguments, the size is taken as a hint about how big each dimension should be. The Array classes uses this only to allocate the initial array object. For multiple dimension arrays, you can also specify how much space is to be allocated initially for each dimension of the array.

Each size argument must a non-negative whole number. If it is 0, the corresponding dimension is initially empty.

Examples:

   a = .array~new()  -- create an new, empty array

of (Class Method)

>>-of-+----------------+---------------------------------------><
      |    +-,----+    |
      |    V      |    |
      +-(----item-+--)-+

Returns a newly created single-index array containing the specified item objects. The first item has index 1, the second has index 2, and so on.

If you use the OF method and omit any argument items, the returned array does not include the indexes corresponding to those you omitted.

Examples:

   a = .array~of("Fred", "Mike", "David")

   do name over a
      say name  -- displays "Fred", "Mike", and "David"
   end

[]

     +-,-----+
     V       |
>>-[---index-+-]-----------------------------------------------><

Returns the same value as the at() method.

Note that the index argument may also be specified as an array of indexes.

[]=

     +-,-----+
     V       |
>>-[---index-+-]=value-----------------------------------------><

This method is the same as the put() method.

Note that the index argument may also be specified as an array of indexes.

allIndexes

>>-allIndexes--------------------------------------------------><

Returns an array of all index positions in the array containing items. For multi-dimension arrays, each returned index will be an array of index values.

Examples:

   a = .array~of("Fred", "Mike", "David")

   do name over a~allIndexes
      say name  -- displays "1", "2", and "3"
   end

   a~remove(2)  -- remove second item

   do name over a~allIndexes
      say name  -- displays "1" and "3"
   end

allItems

>>-allItems----------------------------------------------------><

Returns an array of all items contained in the array.

Examples:

   a = .array~of("Fred", "Mike", "David")

   do name over a~allItems
      say name  -- displays "Fred", "Mike", and "David"
   end

   a~remove(2)  -- remove second item

   do name over a~allItems
      say name  -- displays "Fred" and "David"
   end

append

>>-append(item)------------------------------------------------><

Appends an item to the array after the last item (the item with the highest index). The return value is the index of newly added item.

Examples:

   a = .array~of("Mike", "Rick")
   a~append("Fred")  -- a = .array~of("Mike", "Rick", "Fred")

at

       +-,-----+
       V       |
>>-at(---index-+-)---------------------------------------------><

Returns the item associated with the specified index or indexes. If the array has no item associated with the specified index or indexes, this method returns the Nil object.

Note that the index argument may also be specified as an array of indexes.

Examples:

   a = .array~of("Mike", "Rick")
   say a~at(2)  -- says: "Rick"

dimension

>>-dimension-+-----+-------------------------------------------><
             +-(n)-+

Returns the current size (upper bound) of dimension n (a positive whole number). If you omit n, this method returns the dimensionality (number of dimensions) of the array. If the number of dimensions has not been determined, 0 is returned.

Examples:

   a = .array~of(,"Mike", "Rick")
   say a~dimension     -- says: 1 (number of dimensions in the array)
   say a~dimension(1)  -- says: 3 (upper bound of dimension one)

   a = .array~new~~put("Mike",1,1)~~put("Rick",1,2)
   say a~dimension     -- says: 2 (number of dimensions in the array)
   say a~dimension(1)  -- says: 1 (upper bound of dimension one)
   say a~dimension(2)  -- says: 2 (upper bound of dimension two)

empty

>>-empty-------------------------------------------------------><

Removes all items from the array.

Examples:

   a = .array~of("Mike", "Rick", "Fred", "Rick")
   a~empty  -- a = .array~new

first

>>-first-------------------------------------------------------><

Returns the index of the first item in the array or the Nil object if the array is empty. For multi-dimention arrays, the index is returned as an array of index values.

Examples:

   a = .array~of("Mike", "Rick", "Fred", "Rick")
   say a~first  -- says: 1
   a = .array~of(,"Mike", "Rick")
   say a~first  -- says: 2

hasIndex

             +-,-----+
             V       |
>>-hasIndex(---index-+-)---------------------------------------><

Returns 1 (true) if the array contains an item associated with the specified index or indexes. Returns 0 (false) otherwise.

Note that the index argument may also be specified as an array of indexes.

Examples:

   a = .array~of("Mike", "Rick", "Fred", "Rick")
   say a~hasIndex(2)  -- says: 1
   say a~hasIndex(5)  -- says: 0

hasItem

>>-hasItem(item)-----------------------------------------------><

Returns 1 (true) if the array contains the specified item at any index location. Returns 0 (false) otherwise. Item equality is determined by using the == method of item.

Examples:

   a = .array~of("Mike", "Rick", "Fred", "Rick")
   say a~hasItem("Rick")  -- says: 1
   say a~hasItem("Mark")  -- says: 0

index

>>-index(item)-------------------------------------------------><

Returns the index of the specified item within the array. If the target item appears at more than one index, the first located index will be returned. For multi-dimension arrays, the index is returned as an array of index values. If the array does not contain the specified item, .nil is returned. Item equality is determined by using the == method of item.

Examples:

   a = .array~of("Mike", "Rick", "Fred", "Rick")
   say a~index("Rick")  -- says: 2

isEmpty

>>-isEmpty-----------------------------------------------------><

Returns 1 (true) if the array is empty. Returns 0 (false) otherwise.

Examples:

   a = .array~new
   say a~isEmpty  -- says: 1
   a[1] = "1"
   say a~isEmpty  -- says: 0

items

>>-items-------------------------------------------------------><

Returns the number of items in the collection.

Examples:

   a = .array~of("Fred", , "Mike", , "David")
   say a~items  -- says: 3

last

>>-last--------------------------------------------------------><

Returns the index of the last item in the array or the Nil object if the array is empty. For multi-dimension arrays, index is returned as an array of index items.

Examples:

   a = .array~of("Fred", , "Mike", , "David")
   say a~last  -- says: 5

makeArray

>>-makeArray---------------------------------------------------><

Returns a single-index array with the same number of items as the receiver object. Any index with no associated item is omitted from the new array. Items in the new array will have the same order as the source array. Multi-dimension arrays arrays will be converted into a non-sparse single dimension array.

Examples:

   a = .array~of("Fred", , "Mike", , "David")
   b = a~makeArray  -- b = .array~of("Fred", "Mike", "David")

makeString

                         +-,separator-+
               +-(LINE)--+------------+-+
>>-makeString(-+---------+--------------+-)--------------------><
               +-(CHAR)--+

Returns a string that contains the data of an array. The elements of the array are treated either in line or character format, starting at the first element in the array. The line format is the default. If the line format is use, a separator string can be specified. The separator will be used between concatenated elements instead of the default line end separator.

Examples:

See toString for examples.

next

>>-next(index)-------------------------------------------------><

Returns the index of the item that follows the array item having index index or returns the Nil object if the item having that index is last in the array. For multi-dimention arrays, the same ordering used by the allItems method is used to determine the next position and the index is returned as an array of index values.

Note that the index argument may also be specified as an array of indexes.

Examples:

   a = .array~of("Fred", , "Mike", , "David")
   say a~next(3)  -- says: 5

previous

>>-previous(index)---------------------------------------------><

Returns the index of the item that precedes the array item having index index or the Nil object if the item having that index is first in the array. For multi-dimention arrays, the same ordering used by the allItems method is used to determine the previous position and the index is returned as an array of index values.

Note that the index argument may also be specified as an array of indexes.

Examples:

   a = .array~of("Fred", , "Mike", , "David")
   say a~previous(3)  -- says: 1

put

            +--------+
            V        |
>>-put(item---,index-+-)---------------------------------------><

Makes the object item a member item of the array and associates it with the specified index or indexes. This replaces any existing item associated with the specified index or indexes with the new item. If the index for a particular dimension is greater than the current size of that dimension, the array is expanded to the new dimension size.

Note that the index argument may also be specified as an array of indexes.

Examples:

a = .array~new
a~put("Fred", 1) -- a = .array~of("Fred")
a~put("Mike", 2) -- a = .array~of("Fred", "Mike")
a~put("Mike", 1) -- a = .array~of("Mike", "Mike")

do name over a
  say name
end

/* Output would be: */

Mike
Mike

remove

           +-,-----+
           V       |
>>-remove(---index-+-)-----------------------------------------><

Returns and removes the member item with the specified index or indexes from the array. If there is no item with the specified index or indexes, the Nil object is returned and no item is removed.

Note that the index argument may also be specified as an array of indexes.

Examples:

   a = .array~of("Fred", "Mike", "Mike", "David")
   a~remove(2)  -- removes "Mike"

removeItem

>>-removeItem(item)--------------------------------------------><

Removes an item from the array. If the target item exists at more than one index, the first located item is removed. Item equality is determined by using the == method of item. The return value is the removed item.

Examples:

   a = .array~of("Fred", "Mike", "Mike", "David")
   a~removeItem("Mike")  -- removes the item at index "2"

section

>>-section(start-+--------+-)----------------------------------><
                 +-,items-+

Returns a new array (of the same class as the receiver) containing selected items from the receiver array. The first item in the new array is the item corresponding to index start in the receiver array. Subsequent items in the new array correspond to those in the receiver array (in the same sequence). If you specify the whole number items, the new array contains only this number of items (or the number of subsequent items in the receiver array, if this is less than items). If you do not specify items, the new array contains all subsequent items of the receiver array. The receiver array remains unchanged. The section() method is valid only for single-index arrays.

Note that the start argument, (the index argument,) may also be specified as an array of indexes.

Examples:

   a = .array~of(1,2,3,4)  -- Loads the array

   b = a~section(2)   -- b = .array~of(2,3,4)
   c = a~section(2,2) -- c = .array~of(2,3)
   d = a~section(2,0) -- d = .array~new

size

>>-size--------------------------------------------------------><

Returns the number of items that can be placed in the array before it needs to be extended. This value is the same as the product of the sizes of the dimensions in the array.

sort

>>-sort--------------------------------------------------------><

Sorts an array of Comparable items into ascending order using an unstable Quicksort algorithm. See Sorting Arrays for details.

sortWith

>>-sortWith(comparator)----------------------------------------><

Sorts an array of items into ascending order using an unstable Quicksort algorithm. Ordering of elements is determined using the comparator argument. See Sorting Arrays for details.

stableSort

>>-stableSort--------------------------------------------------><

Sorts an array of Comparable items into ascending order using a stable Mergesort algorithm. See Sorting Arrays for details.

stableSortWith

>>-stableSortWith(comparator)----------------------------------><

Sorts an array of items into ascending order using a stable Mergesort algorithm. Ordering of elements is determined using the comparator argument. See Sorting Arrays for details.

supplier

>>-supplier----------------------------------------------------><

Returns a Supplier object for the collection. The supplier allows you to iterate over the index/item pairs for the collection. The supplier enumerates the array items in their sequenced order. For multi-dimensional arrays, the supplier index method will return the index values as an array of index numbers.

Examples:

   a = .array~of("Fred", "Mike", "David")
   sup = a~supplier
   a~append("Joe")
   do while sup~available
      say sup~item  -- displays "Fred", "Mike", and "David"
      sup~next
   end

toString

                       +-,separator-+
             +-(LINE)--+------------+-+
>>-toString(-+---------+--------------+-)----------------------><
             +-(CHAR)--+

Returns a string that contains the data of an array (one to n dimensional). The elements of the array are treated either in line or character format, starting at the first element in the array. The line format is the default. If the line format is use, a separator string can be specified. The separator will be used between concatenated elements instead of the default line end separator.

Examples:

   a = .array~of(1,2,3,4)  -- Loads the array

   say a~toString  -- Produces: 1
                   --           2
                   --           3
                   --           4

   say a~toString("c")  -- Produces: 1234

   say a~toString(, ", ")  -- Produces: 1, 2, 3, 4

Examples

array1=.array~of(1,2,3,4)  /* Loads the array */

/* Alternative way to create and load an array */
array2=.array~new(4)  /* Creates array2, containing 4 items */
do i=1 to 4                   /* Loads the array */
  array2[i]=i
end

You can produce the elements loaded into an array, for example:

do i=1 to 4
  say array1[i]
end

If you omit any argument values before arguments you supply, the corresponding indexes are skipped in the returned array:

directions=.array~of("North","South", ,"West")
do i=1 to 4                                  /* Produces: North          */
  say directions[i]                          /*           South          */
                                             /*           The Nil object */
end                                          /*           West           */

Here is an example using the ~~:

z=.array~of(1,2,3)~~put(4,4)
do i = 1 to z~size
  say z[i]              /* Produces:  1 2 3 4 */
end

The Bag Class

A bag is a non-sparse collection that restricts the elements to having an item that is the same as the index. Any object can be placed in a bag, and the same object can be placed in a bag several times.

Figure 5-17. The Bag class and methods

Note: The Bag class also has available class methods that its metaclass, the Class class, defines. It also inherits methods from the Set Collection class, although there are not currently any methods defined in that class.

The Bag class is a subclass of the Relation class. In addition to its own methods, it inherits the methods of the Object class and the Relation class.

of (Class Method)

       +-,----+
       V      |
>>-of(---item-+-)----------------------------------------------><

Returns a newly created bag containing the specified item objects.

[]=

>>-[index]=item------------------------------------------------><

Adds an item to the Bag. This method is the same as the put() method.

difference

>>-difference(argument)----------------------------------------><

Returns a new Bag containing only those items from the receiver that the the argument collection does not contain. The argument can be any collection class object.

hasIndex

>>-hasIndex(index)---------------------------------------------><

Returns 1 (true) if the collection contains any item associated with index index, or 0 (false). Index equality is determined by using the == method of index.

intersection

>>-intersection(argument)--------------------------------------><

Returns a new Bag containing only those items from the receiver that are in also in the argument collection. The argument can be any collection class object.

put

>>-put(item,index)---------------------------------------------><

Makes the object item a member item of the bag and associates it with index index. If the relation already contains any items with index index, this method adds a new member item item with the same index, without removing any existing member items.

putAll

>>-putAll(collection)------------------------------------------><

Adds all items collection to the target bag. The collection argument can be any object that supports a supplier method. Items from collection are added using the item values returned by the supplier.

subset

>>-subset(argument)--------------------------------------------><

Returns 1 (true) if all indexes in the receiver collection are also contained in the argument collection; returns 0 (false) otherwise. The argument can be any collection class object.

union

>>-union(argument)---------------------------------------------><

Returns a new Bag that contains all the items from the receiver collection and selected items from the argument collection. The order in which this method selects items in argument is unspecified. The argument can be any collection class object.

xor

>>-xor(argument)-----------------------------------------------><

Returns a new Bag that contains all items from the receiver collection and the argument collection; items that appear in both collections are removed. The argument can be any collection class object.

Examples

/* Create a bag of fruit */
fruit = .bag~of("Apple", "Orange", "Apple", "Pear")
say fruit~items          /* How many pieces? (4)      */
say fruit~items("Apple") /* How many apples? (2)      */
fruit~remove("Apple")    /* Remove one of the apples. */
fruit~~put("Banana")~put("Orange") /* Add a couple.   */
say fruit~items          /* How many pieces? (5)      */

The CircularQueue Class

The CircularQueue class allows for storing objects in a circular queue of a predefined size. Once the end of the queue has been reached, new item objects are inserted from the beginning, replacing earlier entries. Any object can be placed in the queue and the same object can occupy more than one position in the queue.

Figure 5-18. The CircularQueue class and methods

Note: The CircularQueue class also has available class methods that its metaclass, the Class class, defines.

The collected objects can be processed in FIFO (first in, first out) or in a stack-like LIFO (last in, first out) order.

of (Class Method)

>>-of-+----------------+---------------------------------------><
      |    +-,----+    |
      |    V      |    |
      +-(----item-+--)-+

Returns a newly created circular queue containing the specified item objects. The first item has index 1, the second has index 2, and so on. The number of item objects determines the size of the circular queue.

init

>>-init--------------------------------------------------------><

Performs initialization of the circular queue.

makeArray

>>-makeArray(-+---------+-)------------------------------------><
              +--order--+

Returns a single-index array containing the items of the circular queue in the specified order.

The following order can be used. (Only the capitalized letter is needed; all characters following it are ignored.)

Fifo

First-in, first-out order. This is the default.

Lifo

Last-in, first-out order (stacklike).

push

>>-push(item-+------------+)-------------------------------------><
             +--,option---+

Makes the object item a member item of the circular queue, inserting the item object in front of the first item in the queue. The pushed item object will be the new first item in the circular queue.

If the circular queue is full, than the last item stored in the circular queue will be deleted, before the insertion takes place. In this case the deleted item will be returned, otherwise .nil.

If option is specified, it may be "Normal" or "Unique". The default is "Normal". Only the first letter of the option capitalized letter is required; all characters following it are ignored. If option is 'Unique', any matching item already in the queue will be removed before before item is added to the queue. removed before the operation is performed. This allows you to maintain a list like the recent files list of an editor.

queue

              +--,Normal---+
>>-queue(item-+------------+)----------------------------------><
              +--,Unique---+

Makes the object item a member item of the circular queue, inserting the item at the end of the circular queue.

If the circular queue is full, than the first item will be deleted, before the insertion takes place. In this case the deleted item will be returned, otherwise .nil.

If option is specified, it may be "Normal" or "Unique". The default is "Normal". Only the first letter of the option capitalized letter is required; all characters following it are ignored. If option is 'Unique', any matching item already in the queue will be removed before before item is added to the queue. removed before the operation is performed. This allows you to maintain a list like the recent files list of an editor.

resize

>>-resize(-newSize-+----------+-)------------------------------><
                   +--,order--+

Resizes the circular queue object to be able to contain newSize items. If the previous size was larger than newSize, any extra items are removed in the specified order.

The following order can be used. (Only the capitalized letter is needed; all characters following it are ignored.)

Fifo

First-in, first-out. This keeps the most recently added items. This is the default action.

Lifo

Last-in, first-out (stacklike). This removes the most recently added items.

Note:: Resizing with a value of 0 removes all items from the circular queue.

size

>>-size--------------------------------------------------------><

Returns the maximum number of objects that can be stored in the circular queue.

string

           +--","------+  +-,-Fifo--+
>>-string(-+-----------+--+---------+-)------------------------><
           +-delimiter-+  +-,-order-+

Returns a string object that concatenates the string values of the collected item objects, using the delimiter string to delimit them, in the specified order. The default delimiter is a single comma.

If the delimiter string argument is omitted the comma character (",") is used as the default delimiter string.

The following order can be used. (Only the capitalized letter is needed; all characters following it are ignored.)

Fifo

First-in, first-out. This is the default

Lifo

Last-in, first-out (stacklike)

supplier

>>-supplier(-+----------+-)------------------------------------><
             +--order---+

Returns a Supplier object for the collection. The supplier allows you to iterate over the items that were in the queue at the time of the supplier's creation.

The supplier will iterate over the items in the specified order. (Only the capitalized letter is needed; all characters following it are ignored.)

Fifo

First-in, first-out, default

Lifo

Last-in, first-out (stacklike)

Example

  -- create a circular buffer with five items
u=.circularQueue~of("a", "b", "c", "d", "e")
say "content: ["u"]," "content (LIFO): ["u~string("->","L")"]"
say

u~resize(4, "FIFO")     -- resize fifo-style (keep newest)
say "after resizing to 4 items in FIFO style (keeping the newest):"
say "content: ["u"]," "content (LIFO): ["u~string("->","L")"]"
say

u~resize(2, "LILO")     -- resize lifo-style (keep oldest)
say "after resizing to 2 items in LIFO style (keeping the oldest):"
say "content: ["u"]," "content (LIFO): ["u~string("->","L")"]"
say

u~resize(0)             -- resize lifo-style (keep oldest)
say "after resizing to 0 items, thereby deleting all items:"
say "content: ["u"]," "content (LIFO): ["u~string("->","L")"]"
say

u~resize(2)             -- resize lifo-style (keep oldest)
say "after resizing to 2, size="u~size "and items="u~items
u~~queue('x')~~queue('y')~~queue('z')
say "after queuing the three items 'x', 'y', 'z':"
say "content: ["u"]," "content (LIFO): ["u~string("->","L")"]"
say

u~~push('1')~~push('2')~~push('3')
say "after pushing the three items '1', '2', '3':"
say "content: ["u"]," "content (LIFO): ["u~string("->","L")"]"
say

Output:

content: [a,b,c,d,e], content (LIFO): [e->d->c->b->a]

after resizing to 4 items in FIFO style (keeping the newest):
content: [b,c,d,e], content (LIFO): [e->d->c->b]

after resizing to 2 items in LIFO style (keeping the oldest):
content: [b,c], content (LIFO): [c->b]

after resizing to 0 items, thereby deleting all items:
content: [], content (LIFO): []

after resizing to 2, size=2 and items=0
after queuing the three items 'x', 'y', 'z':
content: [y,z], content (LIFO): [z->y]

after pushing the three items '1', '2', '3':
content: [3,2], content (LIFO): [2->3]

The Directory Class

A Directory is a MapCollection using unique character string indexes. The items of the collection can be any valid Rexx object.

Figure 5-19. The Directory class and methods

Note: The Directory class also has available class methods that metaclass, the Class class, defines. It also inherits methods from the Map Collection class, although there are not currently any methods defined in that class.

In addition to the standard put() and at() methods defined for Collections, Directories provide access to objects using methods. For example:

mydir = .directory~new
mydir~name = "Mike"   -- same as mydir~put("Mike", "NAME")
say mydir~name        -- same as say mydir['NAME']

new (Class Method)

>>-new---------------------------------------------------------><

Returns an empty Directory object.

[]

>>-[name]------------------------------------------------------><

Returns the item corresponding to name. This method is the same as the at method.

[]=

>>-[name]=item-------------------------------------------------><

Adds or replaces the entry at index name. This method is the same as the put method.

allIndexes

>>-allIndexes--------------------------------------------------><

Returns an array of all the directory indexes, including those of all the setMethod methods.

allItems

>>-allItems----------------------------------------------------><

Returns an array of all items contained in the directory, including those returned by all setMethod methods.

at

>>-at(name)----------------------------------------------------><

Returns the item associated with index name. If a method defined using setMethod is associated with index name, the result of running this method is returned. If the collection has no item or method associated with index name, the Nill object is returned.

Example:

say .environment~at("OBJECT")   /* Produces: "The Object class" */

empty

>>-empty-------------------------------------------------------><

Removes all items from the directory. Empty also removes all methods added using setMethod.

entry

>>-entry(name)-------------------------------------------------><

Returns the directory entry with name name (translated to uppercase). If there is no such entry, name returns the item for any method that setMethod supplied. If there is neither an entry nor a method for name the Nil object is returned.

hasEntry

>>-hasEntry(name)----------------------------------------------><

Returns 1 (true) if the directory has an entry or a method for name name (translated to uppercase), or 0 (false).

hasIndex

>>-hasIndex(name)----------------------------------------------><

Returns 1 (true) if the collection contains any item associated with index name, or 0 (false).

hasItem

>>-hasItem(item)----------------------------------------------><

Returns 1 (true) if the collection contains the item at any index position or otherwise returns 0 (false). Item equality is determined by using the == method of item.

index

>>-index(item)-------------------------------------------------><

Returns the index of the specified item within the directory. If the target item appears at more than one index, the first located index will be returned. If the directory does not contain the specified item, the Nil object is returned. Item equality is determined by using the == method of item.

isEmpty

>>-isEmpty-----------------------------------------------------><

Returns 1 (true) if the directory is empty. Returns 0 (false) otherwise.

items

>>-items-------------------------------------------------------><

Returns the number of items in the collection.

makeArray

>>-makeArray---------------------------------------------------><

Returns a single-index array containing the index objects. The array indexes range from 1 to the number of items. The collection items appear in the array in an unspecified order. (The program should not rely on any order.)

put

>>-put(item,name)----------------------------------------------><

Makes the object item a member item of the collection and associates it with index name. The new item replaces any existing item or method associated with index name.

remove

>>-remove(name)------------------------------------------------><

Returns and removes the member item with index name from a collection. If a method is associated with setMethod for index name, the method is removed and running the method is returned. If there is no item or method with index name, the Nil object is returned.

removeItem

>>-removeItem(item)--------------------------------------------><

Removes an item from the directory. If the target item exists at more than one index, the first located item is removed. The return value is the removed item. Item equality is determined by using the == method of item.

setEntry

>>-setEntry(name-+--------+-)----------------------------------><
                 +-,entry-+

Sets the directory entry with name name (translated to uppercase) to the object entry, replacing any existing entry or method for name. If you omit entry, this method removes any entry or method with this name.

setMethod

>>-setMethod(name-+---------+-)--------------------------------><
                  +-,method-+

Associates entry name name (translated to uppercase) with method method. Thus, the object returns the result of running method when you access this entry. This occurs when you specify name on the at, entry, or remove method. This method replaces any existing item or method for name.

You can specify the name "UNKNOWN" as name. Doing so supplies a method that is run whenever an at() or entry() message specifies a name for which no item or method exists in the collection. This method's first argument is the specified directory index. This method has no effect on the action of any hasEntry, hasIndex, items, remove, or supplier message sent to the collection.

The method can be a string containing a method source line instead of a method object. Alternatively, an array of strings containing individual method lines can be passed. In either case, an equivalent method object is created.

If you omit method, setMethod() removes the entry with the specified name.

supplier

>>-supplier----------------------------------------------------><

Returns a Supplier object for the collection. The supplier allows you to iterate over the index/item pairs in the directory at the time the supplier was created. The supplier iterates the items in an unspecified order.

unknown

>>-unknown(messagename,messageargs)----------------------------><

Runs either the entry or setEntry method, depending on whether messagename ends with an equal sign. If messagename does not end with an equal sign, this method runs the entry() method, passing messagename as its argument. The messageargs argument is ignored. The entry() method is the return result.

If messagename does end with an equal sign, this method runs the setEntry() method, passing the first part of messagename (up to, but not including, the final equal sign) as its first argument, and the first item in the array messageargs as its second argument. In this case, unknown() returns no result.

unsetMethod

>>-unsetMethod(name)-------------------------------------------><

Removes the association between entry name name (translated to uppercase) and a method.

xor

>>-xor(argument)-----------------------------------------------><

Returns a new Directory object containing all items from the receiver collection and the argument collection; all indexes that appear in both collections are removed. The argument can be any collection class object. The argument must also allow all of the index values in the receiver collection.

Examples

/******************************************************************************/
/*  A Phone Book Directory program                                            */
/*  This program demonstrates use of the directory class.                     */
/******************************************************************************/

/* Define an UNKNOWN method that adds an abbreviation lookup feature.         */
/* Directories do not have to have an UNKNOWN method.                         */
book = .directory~new~~setMethod("UNKNOWN", .methods["UNKNOWN"])

book["ANN" ] = "Ann B. ....... 555-6220"
book["ann" ] = "Little annie . 555-1234"
book["JEFF"] = "Jeff G. ...... 555-5115"
book["MARK"] = "Mark C. ...... 555-5017"
book["MIKE"] = "Mike H. ...... 555-6123"
book~Rick    = "Rick M. ...... 555-5110"  /* Same as book["RICK"] = ...       */

Do i over book                 /* Iterate over the collection                 */
  Say book[i]
end i

Say ""                         /* Index lookup is case sensitive...           */
Say book~entry("Mike")         /* ENTRY method uppercases before lookup       */
Say book["ANN"]                /* Exact match                                 */
Say book~ann                   /* Message sends uppercase before lookup       */
Say book["ann"]                /* Exact match with lowercase index            */

Say ""
Say book["M"]                  /* Uses UNKNOWN method for lookup              */
Say book["Z"]
Exit

/* Define an unknown method to handle indexes not found.                      */
/* Check for abbreviations or indicate listing not found                      */
::Method unknown
  Parse arg at_index
  value = ""
  Do i over self
    If abbrev(i, at_index) then do
      If value <> "" then value = value", "
      value = value || self~at(i)
    end
  end i
  If value = "" then value = "No listing found for" at_index
  Return value

The List Class

A list is a non-sparse sequenced collection similar to the Array Class to which you can add new items at any position in the sequence. The List creates a new index value whenever an item is added to the list and the associated index value remains valid for that item regardless of other additions or removals. Only indexes the list object generates are valid i.e. the list is never a sparse list and the list object will not modify indexes for items in the list.

Figure 5-20. The List class and methods

Note: The List class also has available class methods that its metaclass, metaclass, the Class class, defines. It also inherits methods from the Ordered Collection class, although there are not currently any methods defined in that class.

new (Class Method)

>>-new---------------------------------------------------------><

Returns a new empty List object.

of (Class Method)

       +-,----+
       V      |
>>-of(---item-+-)----------------------------------------------><

Returns a newly created list containing the specified item objects in the order specified.

[]

>>-[index]-----------------------------------------------------><

Returns the item located at index. This is the same as the at method.

[]=

>>-[index]=item------------------------------------------------><

Replaces the item at index with item. This method is the same as the put method.

allIndexes

>>-allIndexes--------------------------------------------------><

Returns an array of all indexes contained in the list in the same order they are used in the list.

allItems

>>-allItems----------------------------------------------------><

Returns an array of all items contained in the list in list iteration order.

append

>>-append(item)------------------------------------------------><

Appends item to the end of the list, returning the index associated with item.

at

>>-at(index)---------------------------------------------------><

Returns the item associated with index index. Returns the Nil object if the list has no item associated with index.

empty

>>-empty-------------------------------------------------------><

Removes all items from the list.

first

>>-first-------------------------------------------------------><

Returns the index of the first item in the list or the Nil object if the list is empty.

firstItem

>>-firstItem---------------------------------------------------><

Returns the first item in the list or the Nil object if the list is empty.

Example:

musketeers=.list~of(Porthos,Athos,Aramis) /* Creates list MUSKETEERS      */
item=musketeers~firstItem                 /* Gives first item in list     */
                                          /* (Assigns "Porthos" to item)  */

hasIndex

>>-hasIndex(index)---------------------------------------------><

Returns 1 (true) if the list contains any item associated with index index, or 0 (false).

hasItem

>>-hasItem(item)----------------------------------------------><

Returns 1 (true) if the list contains the item at any index position or otherwise returns 0 (false). Item equality is determined by using the == method of item.

index

>>-index(item)-------------------------------------------------><

Returns the index of the specified item within the list. If the target item appears at more than one index, the first located index will be returned. Returns the Nil object if the list does not contain the specified item. Item equality is determined by using the == method of item.

insert

>>-insert(item-+--------+-)------------------------------------><
               +-,index-+

Returns a list-supplied index for item item, which is added to the list. The inserted item follows an existing item with index index in the list ordering. If index is the Nil object, item becomes the first item in the list. If you omit index, the item becomes the last item in the list.

Inserting an item in the list at position index will cause the items in the list after position index to have their relative positions shifted by the list object. The index values for any items in the list are not modified by the insertion.

musketeers=.list~of(Porthos,Athos,Aramis) /* Creates list MUSKETEERS        */
                                          /* consisting of: Porthos         */
                                          /*                Athos           */
                                          /*                Aramis          */
index=musketeers~first                    /* Gives index of first item      */
musketeers~insert("D'Artagnan",index) /* Adds D'Artagnan after Porthos  */
                                          /* List is now: Porthos           */
                                          /*              D'Artagnan   */
                                          /*              Athos             */
                                          /*              Aramis            */
/* Alternately, you could use */
musketeers~insert("D'Artagnan",.nil) /* Adds D'Artagnan before Porthos */
                                          /* List is now:  D'Artagnan  */
                                          /*               Porthos          */
                                          /*               Athos            */
                                          /*               Aramis           */
/* Alternately, you could use */
musketeers~insert("D'Artagnan")      /* Adds D'Artagnan after Aramis   */
                                          /* List is now:  Porthos          */
                                          /*               Athos            */
                                          /*               Aramis           */
                                          /*               D'Artagnan  */

isEmpty

>>-isEmpty-----------------------------------------------------><

Returns 1 (true) if the list is empty. Returns 0 (false) otherwise.

items

>>-items-------------------------------------------------------><

Returns the number of items in the list.

last

>>-last--------------------------------------------------------><

Returns the index of the last item in the list or the Nil object if the list is empty.

lastItem

>>-lastItem----------------------------------------------------><

Returns the last item in the list or the Nil object if the list is empty.

makeArray

>>-makeArray---------------------------------------------------><

Returns a single-index array containing the list collection items. The array indexes range from 1 to the number of items. The order in which the collection items appear in the array is the same as their sequence in the list collection.

next

>>-next(index)-------------------------------------------------><

Returns the index of the item that follows the list item having index index. Returns the Nil object if index is the end of the list.

previous

>>-previous(index)---------------------------------------------><

Returns the index of the item that precedes the list item having index index. Returns the Nil object if index is the beginning of the list.

put

>>-put(item,index)---------------------------------------------><

Replaces any existing item associated with the specified index with the item. If index does not exist in the list, an error is raised.

remove

>>-remove(index)-----------------------------------------------><

Returns and removes from a collection the member item with index index. If no item has index index, this method returns the Nil object and removes no item.

Removing an item from the list at position index will shift the relative position of items after position index. The index values assigned to those items will not change.

removeItem

>>-removeItem(item)--------------------------------------------><

Removes an item from the list. If the target item exists at more than one index, the first located item is removed. The return value is the removed item. Item equality is determined by using the == method of item.

section

>>-section(start-+--------+-)----------------------------------><
                 +-,items-+

Returns a new list (of the same class as the receiver) containing selected items from the receiver list. The first item in the new list is the item corresponding to index start in the receiver list. Subsequent items in the new list correspond to those in the receiver list (in the same sequence). If you specify the whole number items, the new list contains only this number of items (or the number of subsequent items in the receiver list, if this is less than items). If you do not specify items, the new list contains all subsequent items from the receiver list. The receiver list remains unchanged.

supplier

>>-supplier----------------------------------------------------><

Returns a Supplier object for the list. The supplier allows you to iterate over the index/item pairs stored in the list at the time the supplier is created. The iteration is in the same order as the list sequence order.

The Properties Class

A properties object is a collection with unique indexes that are character strings representing names and items that are also restricted to character string values. Properties objects are useful for processing bundles of application option values.

Figure 5-21. The Properties class and methods

Note: The Properties class also has available class methods that its metaclass, the Class class, defines.

load (Class method)

>>-load(source)------------------------------------------------><

Loads a set of properties from source and returns them as a new Properties object. The load source can be either the string name of a file or a stream object. Properties are read from the source as individual lines using linein(). Blank lines and lines with a Rexx line comment ("--") as the first non-blank characters are ignored. Otherwise, the lines are assumed to be of the form "name=value" and are added to the receiver Properties value using name as the index for the value.

new (Class method)

>>-new---------------------------------------------------------><

Returns an empty Properties object.

[]=

>>-[name]=item-------------------------------------------------><

Adds item using the index index. This method is the same as the put() method.

getLogical

>>-getLogical(name-+----------+-)------------------------------><
                   +-,default-+

Returns the value of name as either .true or .false. The raw value of the name may be either the numeric values "0" or "1" or the string values "true" or "false". Any other value will raise a syntax error. If the property name does not exist and default has been specified, the default value will be returned. If default has not been specified, a syntax error is raised for missing values.

getProperty

>>-getProperty(name-+----------+-)-----------------------------><
                    +-,default-+

Returns the value of name. If property name does not exist and default has been specified, the default value will be returned. If default has not been specified, the Nil object is returned.

getWhole

>>-getWhole(name-+----------+-)--------------------------------><
                 +-,default-+

Returns the value of name, validated as being a Rexx whole number. If property name does not exist and default has been specified, the default value will be returned. If default has not been specified, a syntax error is raised for missing values.

load

>>-load(source)------------------------------------------------><

Loads a set of properties into the receiving Properties object from source. The load source can be either the string name of a file or a stream object. Properties are read from the source as individual lines using linein(). Blank lines and lines with a Rexx line comment ("--") as the first non-blank characters are ignored. Otherwise, the lines are assumed to be of the form "name=value" and are added to the receiver Properties value using name as the index for the value. Properties loaded from source that have the same names as existing items will replace the current entries.

put

>>-put(item,name)----------------------------------------------><

Makes the object item a member item of the collection and associates it with index name. The item value must be a character string. The new item replaces any existing item or method associated with index name.

save

>>-save(target)------------------------------------------------><

Saves a set of properties into target. The save target can be either the string name of a file or a stream object. Properties are stored as individual lines using lineout(). The lines are written in the form "name=value". A saved Properties file can be reloaded using the Properties load() method.

setLogical

>>-setLogical(name,value)--------------------------------------><

Sets a logical value in the property bundle. The value argument must be either the numbers "0" or "1", or the logical values .true or .false. The property value will be added with value converted in to the appropriate "true" or "false" string value.

setProperty

>>-setProperty(name,value)-------------------------------------><

Sets a named property in the property bundle. The value argument must be a character string value.

setWhole

>>-setWhole(name,value)----------------------------------------><

Sets a whole number value in the property bundle. The value argument must be a valid Rexx whole number.

The Queue Class

A queue is a non-sparse sequenced collection with whole-number indexes. The indexes specify the position of an item relative to the head (first item) of the queue. Adding or removing an item changes the association of an index to its queue item. You can add items at either the tail or the head of the queue.

Figure 5-22. The Queue class and methods

Note: The Queue class also has available class methods that its metaclass, the Class class, defines. It also inherits methods from the Ordered Collection class.

new (Class Method)

>>-new---------------------------------------------------------><

Returns a new empty Queue object.

of (Class Method)

       +-,----+
       V      |
>>-of(---item-+-)----------------------------------------------><

Returns a newly created queue containing the specified item objects in the order specified.

[]

>>-[index]-----------------------------------------------------><

Returns the item located at index index. This is the same as the at() method.

[]=

>>-[index]=item------------------------------------------------><

Replaces item at index with item. This method is the same as the put() method.

allIndexes

>>-allIndexes--------------------------------------------------><

Returns an array of all index values for the queue. For the Queue class, the indices are integers 1 - items.

allItems

>>-allItems----------------------------------------------------><

Returns an array of all items contained in the queue, in queue order.

append

>>-append(item)------------------------------------------------><

Appends item to the end of the queue, returning the index of the inserted item.

at

>>-at(index)---------------------------------------------------><

Returns the item associated with index index. Returns the Nil object if the collection has no item associated with index.

empty

>>-empty-------------------------------------------------------><

Removes all items from the queue.

first

>>-first-------------------------------------------------------><

Returns the index of the first item in the queue or the Nil object if the queue is empty. The index will always be 1 for non-empty queues.

hasIndex

>>-hasIndex(index)---------------------------------------------><

Returns 1 (true) if the queue contains any item associated with index index, or 0 (false).

hasItem

>>-hasItem(item)----------------------------------------------><

Returns 1 (true) if the queue contains the item at any index position or otherwise returns 0 (false). Item equality is determined by using the == method of item.

index

>>-index(item)-------------------------------------------------><

Returns the index of the specified item within the queue. If the target item appears at more than one index, the first located index will be returned. Returns the Nil object if the queue does not contain the specified item. Item equality is determined by using the == method of item.

insert

>>-insert(item-+--------+-)------------------------------------><
               +-,index-+

Returns a queue-supplied index for item, which is added to the queue. The inserted item follows any existing item with index index in the queue ordering. If index is the Nil object, item is inserted at the head of the queue. If you omit index, item becomes the last item in the queue.

Inserting an item in the queue at position index will cause the items in the queue after position index to have their indexes modified by the queue object.

musketeers=.queue~of(Porthos,Athos,Aramis) /* Creates queue MUSKETEERS       */
                                           /* consisting of: Porthos         */
                                           /*                Athos           */
                                           /*                Aramis          */
index=musketeers~first                     /* Gives index of first item      */
musketeers~insert("D'Artagnan",index) /* Adds D'Artagnan after Porthos  */
                                           /* List is now: Porthos           */
                                           /*              D'Artagnan   */
                                           /*              Athos             */
                                           /*              Aramis            */
/* Alternately, you could use */
musketeers~insert("D'Artagnan",.nil)  /* Adds D'Artagnan before Porthos */
                                           /* List is now:  D'Artagnan  */
                                           /*               Porthos          */
                                           /*               Athos            */
                                           /*               Aramis           */
/* Alternately, you could use */
musketeers~insert("D'Artagnan")       /* Adds D'Artagnan after Aramis   */
                                           /* List is now:  Porthos          */
                                           /*               Athos            */
                                           /*               Aramis           */
                                           /*               D'Artagnan  */

isEmpty

>>-isEmpty-----------------------------------------------------><

Returns 1 (true) if the queue is empty. Returns 0 (false) otherwise.

items

>>-items-------------------------------------------------------><

Returns the number of items in the collection.

last

>>-last--------------------------------------------------------><

Returns the index of the last item in the queue or the Nil object if the queue is empty.

makeArray

>>-makeArray---------------------------------------------------><

Returns a single-index array containing the receiver queue items. The array indexes range from 1 to the number of items. The order in which the queue items appear in the array is the same as their queuing order, with the head of the queue as index 1.

next

>>-next(index)-------------------------------------------------><

Returns the index of the item that follows the queue item having index index or returns the Nil object if the item having that index is last in the queue.

peek

>>-peek--------------------------------------------------------><

Returns the item at the head of the queue. Returns the Nil object if the queue is empty. The collection remains unchanged.

previous

>>-previous(index)---------------------------------------------><

Returns the index of the item that precedes the queue item having index index or the Nil object if the item having that index is first in the queue.

pull

>>-pull--------------------------------------------------------><

Returns and removes the item at the head of the queue. Returns the Nil object if the queue is empty.

push

>>-push(item)--------------------------------------------------><

Adds the object item to the head of the queue.

put

>>-put(item,index)---------------------------------------------><

Replaces any existing item associated with the specified index with the new item. If the index does not exist in the queue, an error is raised.

queue

>>-queue(item)-------------------------------------------------><

Adds the object item to the tail of the queue.

remove

>>-remove(index)-----------------------------------------------><

Returns and removes from a collection the member item with index index. Returns the Nil object if no item has index index.

removeItem

>>-removeItem(item)--------------------------------------------><

Removes an item from the queue. If the target item exists at more than one index, the first located item is removed. The return value is the removed item. Item equality is determined by using the == method of item.

supplier

>>-supplier----------------------------------------------------><

Returns a Supplierobject for the queue. The supplier allows you to iterate over the index/item pair contained in the queue at the time the supplier was created. The supplier iterates the items in their queuing order, with the head of the queue first.

The Relation Class

A relation is a collection with indexes that can be any object. In a relation, each item is associated with a single index, but there can be more than one item with the same index (unlike a table, which can contain only one item for any index).

Figure 5-23. The Relation class and methods

Note: The Relation class also has available class methods that its metaclass, the Class class, defines. It also inherits methods from the Map Collection class.

new (Class Method)

>>-new---------------------------------------------------------><

Returns an empty Relation object.

[]

>>-[index]-----------------------------------------------------><

Returns an item associated with index. Thie is the same as the at() method.

[]=

>>-[index]=item------------------------------------------------><

Adds item to the relation associated with index index. This is the same as the put() method.

allAt

>>-allAt(index)------------------------------------------------><

Returns a single-index array containing all the items associated with index index. Items in the array appear in an unspecified order. Index equality is determined by using the == method of index.

allIndex

>>-allIndex(item)----------------------------------------------><

Returns a single-index array containing all indexes for item item, in an unspecified order. Item equality is determined by using the == method of item.

allIndexes

>>-allIndexes--------------------------------------------------><

Returns an array of all indexes contained in the Relation. The returned array will have one index for every item stored in the relation, including duplicates. Duplicate indexes can be removed easily by converted the array to a set.

   -- retrieve the unique index items
   indexes = .set~new~union(relation~allindexes)

allItems

>>-allItems----------------------------------------------------><

Returns an array of all items contained in the relation.

at

>>-at(index)---------------------------------------------------><

Returns the item associated with index index. If the relation contains more than one item associated with index index, the item returned is unspecified. (The program should not rely on any particular item being returned.) Returns the Nil object if the relation has no item associated with index index. Index equality is determined by using the == method of index.

difference

>>-difference(argument)----------------------------------------><

Returns a new Relation containing only those items that the argument collection does not contain (with the same associated index). The argument can be any collection class object.

empty

>>-empty-------------------------------------------------------><

Removes all items from the relation.

hasIndex

>>-hasIndex(index)---------------------------------------------><

Returns 1 (true) if the collection contains any item associated with index index, or 0 (false). Index equality is determined by using the == method of index.

hasItem

>>-hasItem(item-+--------+-)-----------------------------------------><
                +-,index-+

Returns 1 (true) if the relation contains the member item item, 0 (false). If index is specified, hasIndex() will only return true if the relation contains the pairing of item associated with index index. Item and index equality is determined by using the == method.

index

>>-index(item)-------------------------------------------------><

Returns the index for item item. If there is more than one index associated with item item, the one returned is not defined. Item equality is determined by using the == method of item.

intersection

>>-intersection(argument)--------------------------------------><

Returns a new collection (of the same class as the receiver) containing only those items that are in both the receiver collection and the argument collection with the same associated index. The argument can be any collection class object.

isEmpty

>>-isEmpty-----------------------------------------------------><

Returns 1 (true) if the relation is empty. Returns 0 (false) otherwise.

items

>>-items-+---------+-------------------------------------------><
         +-(index)-+

Returns the number of relation items with index index. If you specify no index, this method returns the total number of items associated with all indexes in the relation. Index equality is determined by using the == method of index.

makeArray

>>-makeArray---------------------------------------------------><

Returns a single-index array containing the index objects. The collection items appear in the array in an unspecified order.

put

>>-put(item,index)---------------------------------------------><

Makes the object item a member item of the relation and associates it with index index. If the relation already contains any items with index index, this method adds a new member item item with the same index, without removing any existing member items.

remove

>>-remove(index)-----------------------------------------------><

Returns and removes from a relation the member item with index index. If the relation contains more than one item associated with index index, the item returned and removed is unspecified. Returns the Nil object if no item has index index. Index equality is determined by using the == method of index.

removeItem

>>-removeItem(item,index)--------------------------------------><

Returns and removes from a relation the member item item (associated with index index). Returns the Nil object if value is not a member item associated with index index. If item is the only member with index) then the index) is also removed from the Relation.

subset

>>-subset(argument)--------------------------------------------><

Returns 1 (true) if all items in the receiver Relation are also contained in the argument collection with the same associated index; returns 0 (false) otherwise. The argument can be any collection class object.

supplier

>>-supplier--+---------+---------------------------------------><
             +-(index)-+

Returns a The Supplier Class object for the relation. The supplier allows you to iterate over all index/item pairs in the relation at the time the supplier was created. The supplier enumerates the items in an unspecified order. If you specify index, the supplier contains all of the items with the specified index.

union

>>-union(argument)---------------------------------------------><

Returns a new collection containing all items from the receiver collection and the argument collection. The argument can be any collection class object.

xor

>>-xor(argument)-----------------------------------------------><

Returns a new collection of the same class as the receiver that contains all items from the receiver collection and the argument collection. All index-item pairs that appear in both collections are removed. The argument can be any collection class object.

Examples

/* Use a relation to express parent-child relationships */
family = .relation~new
family["Henry"] = "Peter"    /* Peter is Henry's child   */
family["Peter"] = "Bridget"  /* Bridget is Peter's child */
family["Henry"] = "Jane"     /* Jane is Henry's child    */

/* Show all children of Henry recorded in the family relation */
henrys_kids = family~allAt("Henry")
Say "Here are all the listed children of Henry:"
Do kid Over henrys_kids
  Say " "kid
End

/* Show all parents of Bridget recorded in the family relation */
bridgets_parents = family~allIndex("Bridget")
Say "Here are all the listed parents of Bridget:"
Do parent Over bridgets_parents
  Say " "parent
End

/* Display all the grandparent relationships we know about. */
checked_for_grandkids = .set~new         /* Records those we have checked      */
Do grandparent Over family               /* Iterate for each index in family   */
  If checked_for_grandkids~hasIndex(grandparent)
    Then Iterate                         /* Already checked this one           */
  kids = family~allat(grandparent)       /* Current grandparent's children     */
  Do kid Over kids                       /* Iterate for each item in kids      */
    grandkids = family~allAt(kid)        /* Current kid's children             */
    Do grandkid Over grandkids           /* Iterate for each item in grandkids */
      Say grandparent "has a grandchild named" grandkid"."
    End
  End
  checked_for_grandkids~put(grandparent) /* Add to already-checked set         */
End

The Set Class

A Set is a collection containing member items where the index is the same as the item (similar to a Bag collection). Any object can be placed in a set. There can be only one occurrence of any object in a set (unlike a Bag collection). Item equality is determined by using the == method.

Figure 5-24. The Set class and methods

Note: The Set class also has available class methods that its metaclass, the Class class, defines.

The Set class is a subclass of the Table class. In addition to its own methods, it inherits the methods of the Object class (see The Object Class) and the Table class. It also inherits methods from the Set Collection class.

of (Class Method)

       +-,----+
       V      |
>>-of(---item-+-)----------------------------------------------><

Returns a newly created set containing the specified item objects.

[]=

>>-[index]=item------------------------------------------------><

Add an item to the Set. This method is the same as the put() method.

intersection

>>-intersection(argument)--------------------------------------><

Returns a new collection (of the same class as the receiver) containing only those items from the receiver whose indexes are in both the receiver collection and the argument collection. The argument can be any collection class object. The argument must also allow all of the index values in the receiver collection.

put

>>-put(item-+--------+-)-----------------------------------------><
            +-,index-+

Adds item to the Set. If there is an equivalent item in the Set, the exiting item will be replaced by the new instance. Item equality is determined by using the == method of item. If index is specified, it must be the same as item.

putAll

>>-putAll(collection)------------------------------------------><

Adds all items collection to the target set. The collection argument can be any object that supports a supplier method. Items from collection are added using the item values returned by the supplier. If duplicate items exist in collection, the last item provided by the supplier will overwrite previous items with the same index.

subset

>>-subset(argument)--------------------------------------------><

Returns 1 (true) if all items in the receiver collection are also contained in the argument collection; returns 0 (false) otherwise. The argument can be any collection class object. The argument must also allow all of the index values in the receiver collection.

union

>>-union(argument)---------------------------------------------><

Returns a new Set contains all the items from the receiver collection and selected items from the argument collection. This method includes an item from argument in the new collection only if there is no item already in the in the receiver collection and the method has not already included a matching item. The order in which this method selects items in argument is unspecified. The argument can be any collection class object. The argument must also allow all of the index values in the receiver collection.

xor

>>-xor(argument)-----------------------------------------------><

Returns a new Set that contains all items from the receiver collection and the argument collection; all items that appear in both collections are removed. The argument can be any collection class object. The argument must also allow all of the index values in the receiver collection.

The Stem Class

A stem object is a collection with unique indexes that are character strings.

Figure 5-25. The Stem class and methods

Note: The Stem class also has available class methods that its metaclass, the Class class, defines. It also inherits methods from the Map Collection class.

Stems are automatically created whenever a Rexx stem variable or Rexx compound variable is used. For example:

a.1 = 2

creates a new stem collection with the name A. and assigns it to the Rexx variable A.; it also assigns the value 2 to entry 1 in the collection.

The value of an uninitialized stem index is the stem object NAME concatenated with the derived stem index. For example

say a.[1,2]  -- implicitly creates stem object with name "A."
-- displays "A.1.2"

a = .stem~new("B.")
say a[1,2]     -- displays "B.1.2"

In addition to the items explicitly assigned to the collection indexes, a value may be assigned to all possible stem indexes. The []= method (with no index argument) will assign the target value to all possible stem indexes. Following assignment, a reference to any index will return the new value until another value is assigned or the index is dropped.

The [] method (with no index specified) will retrieve any globally assigned value. By default, this returns the stem NAME value.

In addition to the methods defined in the following, the Stem class removes the methods =, ==, \=, \==, <>, and >< using the DEFINE method.

new (Class Method)

>>-new-+--------+----------------------------------------------><
       +-(name)-+

Returns a new stem object. If you specify a string name, this value is used to create the derived name of compound variables. The default stem name is a null string ("").

[]

     +-,---------+
     V           |
>>-[---+-------+-+-]-------------------------------------------><
       +-index-+

Returns the item associated with the specified indexes. Each index is an expression; use commas to separate the expressions. The Stem object concatenates the index string values, separating them with a period (.), to create a derived index. A null string ("") is used for any omitted expressions. The resulting string is the index of the target stem item. If the stem has no item associated with the specified final index, the stem default value is returned. If a default value has not been set, the stem name concatenated with the final index string is returned.

If you do not specify index, the stem default value is returned. If no default value has been assigned, the stem name is returned.

Note: You cannot use the [] method in a DROP or PROCEDURE instruction.

[]=

     +-,---------+
     V           |
>>-[---+-------+-+-]=value-------------------------------------><
       +-index-+

Makes the value a member item of the stem collection and associates it with the specified index. The final index is derived by concatenation each of the index arguments together with a "." separator. If you specify no index arguments, a new default stem value is assigned. Assigning a new default value will re-initialize the stem and remove all existing assigned indexes.

allIndexes

>>-allIndexes--------------------------------------------------><

Returns an array of all the stem tail names used in the stem.

allItems

>>-allItems----------------------------------------------------><

Returns an array of all items contained in the stem.

at

>>-at(tail)----------------------------------------------------><

Returns the item associated with the specified tail. The Nil object is returned if the stem has no item associated with the specified tail.

empty

>>-empty-------------------------------------------------------><

Removes all items from the stem.

hasIndex

>>-hasIndex(tail)----------------------------------------------><

Returns 1 (true) if the collection contains any item associated with a stem tail tail, or 0 (false).

hasItem

>>-hasItem(value)----------------------------------------------><

Returns 1 (true) if the collection contains the value at any tail position or otherwise returns 0 (false). Item equality is determined by using the == method of item.

index

>>-index(item)-------------------------------------------------><

Returns the index of the specified item within the stem. Returns the Nil object if the stem does not contain the specified item. Item equality is determined by using the == method of item.

isEmpty

>>-isEmpty-----------------------------------------------------><

Returns 1 (true) if the stem is empty. Returns 0 (false) otherwise.

items

>>-items-------------------------------------------------------><

Returns the number of items in the collection.

makeArray

>>-makeArray---------------------------------------------------><

Returns an array of all stem indexes that currently have an associated value. The items appear in the array in an unspecified order.

put

>>-put(item,tail)----------------------------------------------><

Replaces any existing item associated with the specified tail with the new item item.

remove

>>-remove(tail)------------------------------------------------><

Returns and removes from the stem the member item with index tail. Returns the Nil object if no item has index tail.

removeItem

>>-removeItem(item)--------------------------------------------><

Removes an item from the stem. If the target item exists at more than one tail, the first located item is removed. Item equality is determined by using the == method of item. The return value is the removed item.

request

>>-request(classid)--------------------------------------------><

This method requests conversion to a specific class. All conversion requests except Array are forwarded to the stem's current stem default value. Returns the result of the Stem class makeArray method, if the requested class is Array. For all other classes, request forwards the message to the stem object's default value.

supplier

>>-supplier----------------------------------------------------><

Returns a Supplier object for the stem. The supplier allows you to iterate though the index/item pairs contained in the Stem object at the time the supplier was created. The supplier iterams the items in an unspecified order.

toDirectory

>>-toDirectory----------------------------------------------------><

Returns a Directory object for the stem. The directory will contain a name/value pair for each stem index with a directly assigned value.

unknown

>>-unknown-(messagename,messageargs)---------------------------><

Reissues or forwards all unknown messages to the stem's current default value. For additional information, see Defining an unknown Method.

The Table Class

A table is a collection with indexes that can be any object. In a table, each item is associated with a single index, and there can be only one item for each index (unlike a relation, which can contain more than one item with the same index). Index equality is determined by using the == method.

Figure 5-26. The Table class and methods

Note: The Table class also has available class methods that its metaclass, the Class class, defines. It also inherits methods from the Map Collection class.

new (Class Method)

>>-new---------------------------------------------------------><

Returns an empty Table object.

[]

>>-[index]-----------------------------------------------------><

Returns the item associated with index. This is the same as the at() method.

[]=

>>-[index]=item------------------------------------------------><

Adds item to the table at index index. This method is the same as the put() method.

allIndexes

>>-allIndexes--------------------------------------------------><

Returns an array of all indexes contained in the table.

allItems

>>-allItems----------------------------------------------------><

Returns an array of all items contained in the table.

at

>>-at(index)---------------------------------------------------><

Returns the item associated with index index. Returns the Nil object if the collection has no item associated with index.

empty

>>-empty-------------------------------------------------------><

Removes all items from the table.

hasIndex

>>-hasIndex(index)---------------------------------------------><

Returns 1 (true) if the collection contains any item associated with index index, or 0 (false).

hasItem

>>-hasItem(value)----------------------------------------------><

Returns 1 (true) if the collection contains the value at any index position or otherwise returns 0 (false). Item equality is determined by using the == method of item.

index

>>-index(item)-------------------------------------------------><

Returns the index of the specified item within the table. If the target item appears at more than one index, the first located index will be returned. Returns the Nil object if the table does not contain the specified item. Item equality is determined by using the == method of item.

isEmpty

>>-isEmpty-----------------------------------------------------><

Returns 1 (true) if the table is empty. Returns 0 (false) otherwise.

items

>>-items-------------------------------------------------------><

Returns the number of items in the collection.

makeArray

>>-makeArray---------------------------------------------------><

Returns a single-index array containing the index objects. The array indexes range from 1 to the number of items. The collection items appear in the array in an unspecified order.

put

>>-put(item,index)---------------------------------------------><

Makes the object item a member item of the collection and associates it with index index. The new item replaces any existing items associated with index index.

remove

>>-remove(index)-----------------------------------------------><

Returns and removes the table item with index index. Returns the Nil object if no item has index index.

removeItem

>>-removeItem(item)--------------------------------------------><

Removes an item from the table. If the target item exists at more than one index, the first located item is removed. The return value is the removed item. Item equality is determined by using the == method of item.

supplier

>>-supplier----------------------------------------------------><

Returns a Supplier object for the collection. The supplier allows you iterate over the index/item pairs contained in the table at the time the supplier was created. The supplier iterates over the items in an unspecified order.

The IdentityTable Class

An identity table is a collection with indexes that can be any object. In an identity table, each item is associated with a single index, and there can be only one item for each index. Index and item matches in an identity table are made using an object identity comparison. That is, an index will only match if the same instance is used in the collection.

Figure 5-27. The IdentityTable class and methods

Note: The IdentityTable class also has available class methods that its metaclass, the Class class, defines. It also inherits methods from the Map Collection class.

new (Class Method)

>>-new---------------------------------------------------------><

Returns an empty IdentityTable object.

[]

>>-[index]-----------------------------------------------------><

Returns the item associated with index. This is the same as the at() method.

[]=

>>-[index]=item------------------------------------------------><

Adds item to the table at index index. This method is the same as the put() method.

allIndexes

>>-allIndexes--------------------------------------------------><

Returns an array of all indices contained in the table.

allItems

>>-allItems----------------------------------------------------><

Returns an array of all items contained in the table.

at

>>-at(index)---------------------------------------------------><

Returns the item associated with index index. Returns the Nil object if the collection has no item associated with index.

empty

>>-empty-------------------------------------------------------><

Removes all items from the table.

hasIndex

>>-hasIndex(index)---------------------------------------------><

Returns 1 (true) if the collection contains any item associated with index index, or 0 (false).

hasItem

>>-hasItem(item)-----------------------------------------------><

Returns 1 (true) if the collection contains the item at any index position or otherwise returns 0 (false).

index

>>-index(item)-------------------------------------------------><

Returns the index of the specified item within the table. If the target item appears at more than one index, the first located index will be returned. Returns the Nil object if the table does not contain the specified item.

isEmpty

>>-isEmpty-----------------------------------------------------><

Returns 1 (true) if the table is empty. Returns 0 (false) otherwise.

items

>>-items-------------------------------------------------------><

Returns the number of items in the collection.

makeArray

>>-makeArray---------------------------------------------------><

Returns a single-index array containing the index objects. The array indexes range from 1 to the number of items. The collection items appear in the array in an unspecified order.

put

>>-put(item,index)---------------------------------------------><

Makes the object item a member item of the collection and associates it with index index. The new item replaces any existing items associated with index index.

remove

>>-remove(index)-----------------------------------------------><

Returns and removes from a collection the member item with index index. Returns the Nil object if no item has index index.

removeItem

>>-removeItem(item)--------------------------------------------><

Removes an item from the table. If the target item exists at more than one index, the first located item is removed. The return value is the removed item.

supplier

>>-supplier----------------------------------------------------><

Returns a Supplier object for the collection. The supplier allows you iterate over the index/item pairs contained in the table at the time the supplier was created. The supplier iterates over the items in an unspecified order.

Sorting Arrays

Any non-sparse Array instance can have its elements placed into sorted order using the sort method of the Array class. The simplest sort is sorting an array of strings. For example:

myArray = .array~of("Zoe", "Fred", "Xavier", "Andy")
myArray~sort

do name over myArray
   say name
end

will display the names in the order "Andy", "Fred", "Xavier", "Zoe".

The sort method orders the strings by using the compareTo method of the String class. The compareTo method knows how to compare one string to another, and returns the values -1 (less than), 0 (equal), or 1 (greater than) to indicate the relative ordering of the two strings.

Sorting non-strings

Sorting is not limited to string values. Any object that inherits the Comparable mixin class and implements a compareTo method can be sorted. The DateTime Class and TimeSpan Class are examples of built-in Rexx classes that can be sorted. Any user created class may also implement a compareTo() method to enable sorting. For example, consider the following simple class:

    ::class Employee inherit Comparable
    ::method init
      expose id name
      use arg id, name
    ::method id attribute
    ::method name attribute
    ::method compareTo
      expose id
      use arg other
      return id~compareTo(other~id)  -- comparison performed using employee id
    ::method string
      expose name
      use arg name
      return "Employee" name

The Employee class implements its sort order using the employee identification number. When the sort method needs to compare two Employee instances, it will call the compareTo method on one of the instances, passing the second instance as an argument. The compareTo method tells the sort method which of the two instances should be first.

    a = .array~new
    a[1] = .Employee~new(654321, "Fred")
    a[2] = .Employee~new(123456, "George")
    a[3] = .Employee~new(333333, "William")

    a~sort

    do employee over a
       say employee    -- sorted order is "George", "William", "Fred"
    end

Sorting with more than one order

The String class compareTo method only implements a sort ordering for an ascending sort using a strict comparison. Frequently it's desirable to override a class-defined sort order or even to sort items that do not implement a compareTo method. To change the sorting criteria, use the Array sortWith method. The sortWith method takes a single argument, which is a Comparator object that implements a compare method. The compare method performs comparisons between pairs of items. Different comparators can be customized for different comparison purposes. For example, the Rexx language provides a DescendingComparator class that will sort items into descending order:

::CLASS 'DescendingComparator' MIXINCLASS Comparator
::METHOD compare
use strict arg left, right
return -left~compareTo(right)

The DescendingComparator merely inverts the result returned by the item compareTo method. Our previous example

myArray = .array~of("Zoe", "Fred", "Xavier", "Andy")
myArray~sortWith(.DescendingComparator~new)

do name over myArray
   say name
end

now displays in the order "Zoe", "Xavier", "Fred", "Andy".

Custom Comparators are simple to create for any sorting purpose. The only requirement is implementing a compare method that knows how to compare pairs of items in some particular manner. For example, to sort our Employee class by name instead of the default employee id, we can use the following simple comparator class:

::CLASS EmployeeNameSorter MIXINCLASS Comparator
::METHOD compare
  use strict arg left, right
  return left~name~compareTo(right~name)  -- do the comparison using the names

Builtin Comparators

Rexx includes a number of built-in Comparators for common sorting operations.

Comparator

Base comparator. The Comparator class just uses the compareTo method of the first argument to generate the result. Using sortWith and a Comparator instance is equivalent to using the sort method and no comparator.

DescendingComparator

The reverse of the Comparator class. The DescendingComparator can be used to sort items in descending order.

InvertingComparator

The InvertingComparator will invert the result returned by another Comparator instance. This comparator can be combined with another comparator instance to reverse the sort order.

CaselessComparator

Like the base comparator, but uses the caselessCompareTo method to determine order. The String class implements caselessCompareTo, so the CaselessComparator can be used to sort arrays of strings independent of case.

ColumnComparator

The ColumnComparator will sort string items using specific substrings within each string item. If sorting is performed on multiple column positions, the stableSortWith method is recommended to ensure the results of previous sort operations are retained.

CaselessColumnComparator

Like the ColumnComparator, but the substring comparisons are done independently of case.

Stable and Unstable Sorts

The default sorting algorithm is a Quicksort. A Quicksort is a very efficient sorting algorithm that does not require any additional memory to implement. Unfortunately, a Quicksort is also an unstable sort. In an unstable sort, items are not guaranteed to maintain their original positions if they compare equal during the sort. Consider the following simple example:

a = .array~of("Fred", "George", "FRED", "Mike", "fred")
a~sortwith(.caselesscomparator~new)
do name over a
  say name
end

This example displays the 3 occurrences of Fred in the order "Fred", "fred", "FRED", even though they compare equal using a caseless comparison.

The Array class implements a second sort algorithm that is available using the stableSort and stableSortWith methods. These methods use a Mergesort algorithm, which is less efficient than the default Quicksort and requires additional memory. The Mergesort is a stable algorithm that maintains the original relative ordering of equivalent items. Our example above, sorted with stableSortWith, would display "Fred", "FRED", "fred".

The Concept of Set Operations

The following sections describe the concept of set operations to help you work with set operators, in particular if the receiver collection class differs from the argument collection class.

Rexx provides the following set-operator methods:

These methods are available to instances of the following collection classes:

result = receiver~setoperator(argument)

where:

receiver

is the collection object receiving the set-operator message.

setoperator

is the set-operator method used.

argument

is the argument collection supplier supplied to the method. It can be an instance of one of the Rexx collection classes or any object that implements a makearray method or supplier method, depending on class of receiver.

The result object is of the same class as the receiver collection object.

The Principles of Operation

A set operation is performed by iterating over the elements of the receiver collection to compare each element of the receiver with each element of the argument collection. The element is defined as the tuple < index,item> (see Determining the Identity of an Item). Depending on the set-operator method and the result of the comparison, an element of the receiver collection is, or is not, included in the resulting collection. A receiver collection that allows for duplicate elements can, depending on the set-operator method, also accept elements of the argument collection after they have been coerced to the type of the receiver collection.

The following examples are to help you understand the semantics of set operations. The collections are represented as a list of elements enclosed in curly brackets. The list elements are separated by a comma.

Set Operations on Collections without Duplicates

Assume that the example sets are A={a,b} and B={b,c,d}. The result of a set operation is another set. The only exception is a subset resulting in a Boolean .true or .false. Using the collection A and B, the different set operators produce the following:

UNION operation

All elements of A and B are united:

A UNION B = {a,b,c,d}

DIFFERENCE operation

The resulting collection contains all elements of the first set except for those that also appear in the second set. The system iterates over the elements of the second set and removes them from the first set one by one.

A DIFFERENCE B = {a}
B DIFFERENCE A = {c,d}

XOR operation

The resulting collection contains all elements of the first set that are not in the second set and all elements of the second set that are not in the first set:

A XOR B = {a,c,d}

INTERSECTION operation

The resulting collection contains all elements that appear in both sets:

A INTERSECTION B = {b}

SUBSET operation

Returns .true if the first set contains only elements that also appear in the second set, otherwise it returns .false:

A SUBSET B = .false
B SUBSET A = .false

Set-Like Operations on Collections with Duplicates

Assume that the example bags are A={a,b,b} and B={b,b,c,c,d}. The result of any set-like operation is a collection, in this case a bag. The only exception is subset resulting in a Boolean .true or .false. Using the collections A and B, the different set-like operators produce the following:

UNION operation

All elements of A and B are united:

A UNION B = {a,b,b,b,b,c,c,d}

DIFFERENCE operation

The resulting collection contains all elements of the first bag except for those that also appear in the second bag. The system iterates over the elements of the second bag and removes them from the first bag one by one.

A DIFFERENCE B = {a}
B DIFFERENCE A = {c,c,d}

XOR operation

The resulting collection contains all elements of the first bag that are not in the second bag and all elements of the second bag that are not in the second bag:

A XOR B = {a,c,c,d}

INTERSECTION operation

The resulting collection contains all elements that appear in both bags:

A INTERSECTION B = {b,b}

SUBSET operation

Returns .true if the first set contains only elements that also appear in the second set, otherwise it returns .false:

A SUBSET B = .false
B SUBSET A = .false

Determining the Identity of an Item

Set operations require the definition of the identity of an element to determine whether a certain element exists in the receiver collection. The element of a collection is conceived as the tuple <index,item>. The index is used as the identification tag associated with the item. Depending on the collection class, the index is an instance of a particular class, for example, the string class for a directory element, an integer for an array, or any arbitrary class for a relation. The Array class is an exception because it can be multidimensional having more than one index. However, as a collection, it is conceptionally linearized by the set operator.

For collection classes that require unique indexes, namely the Set, IdentityTable, Table, Directory, and Stem, an item is identified by its index. For collections of collection classes that allow several items to have the same index, namely the Relation class, an item is identified by both its index and its item. For the Bag and the Set subclasses, where several items can have the same index but index and item must be identical, the item is identified by its index. For Array, List, and Queue classes, the index is derived from an object's position within the collection's order. Items are identified using only item.

When collections with different index semantics are used in set operations, the argument collection is coerced into a collection of the same type as the receiver, and the operation is then performed using the converted collection. The coercion process differs based on the types of both the receiver and the argument collection. According to this concept, an item of a collection is identified for the different receiver categories as follows:

Map Collection

If argument is a MapCollection, then index values are used to determine membership, and items are inserted into the result using the index and item pairs.

If argument is an OrderedCollection or SetCollection, argument is converted into a MapCollection using the collection items as both index and item values. Since the argument collection may contain duplicate items, the converted collection is effectively a Relation instance.

For all other argument objects, the makearray method is used to obtain a set of values which are used as if argument was an OrderedCollection.

Ordered Collection and Set Collection

If argument is an instance of Collection, the matching set is obtained from the allItems method. For any other class of object, the makearray method is used. The hasItem method is used to perform the matching operations between the two collections.

Relation

If argument is a MapCollection, then index values are used to determine membership, and items are inserted into the result using the index and item pairs.

If argument is an OrderedCollection or SetCollection, argument is converted into a MapCollection using the collection items as both index and item values. Since the argument collection may contain duplicate items, the converted collection is effectively a Relation instance.

For all other argument objects, the makearray method is used to obtain a set of values which are used as if argument was an OrderedCollection. All tests for result membership are made using both the index and item values.