Class Ls extends System.Collections.ArrayList

Introduction

This class adds numerous extensions to the Synergy/DE version of System.Collections.Arraylist to enable:

Contents

  1. Introduction
  2. Contents
  3. Explanation of symbols used
  4. Member reference
    1. (constructors)
    2. append, append$, appendflat$, add$, +, |, & - append to a list
    3. car - the first element in a list
    4. cdr - the second and following elements in a list
    5. chop, chop$ - truncate a list
    6. compact, compact$ - remove null elements from a list
    7. contains - determine if an object is a member of a list
    8. copy - copy a list
    9. countif - conditionally count members
    10. deepcopy - copy all nested lists
    11. empty - create a new, empty list
    12. Equals - override instance equality testing
    13. find - find an object that satisfies a condition
    14. findall - find all objects that satisfy a condition
    15. flatten - flatten a list
    16. from - create a list from another list, array, or Hash
    17. intersection - intersection of two lists
    18. issubsetof - determine whether a list is a subset of another list
    19. issupersetof - determine whether a list is a superset of another list
    20. join - join a list to create a string
    21. keyadd - add an association to an alist
    22. keydel - delete an association from an alist
    23. keyfind - find an element of an alist
    24. keyget, [] - get the value associated with a key in an alist
    25. keygetl - get the list of values associated with a key in an alist
    26. keyset, []= - set the value associated with a key in an alist
    27. last - the last item of a list
    28. of - create a list from an object
    29. make_pair - create a list of two objects
    30. map, map$ - map one list to another
    31. mapnonull - map one list to another, excluding nulls
    32. merge, merge$ - merge two lists
    33. mergesort - sort a list, using MergeSort
    34. pop - remove and return the first item in a list
    35. poplast - remove and return the last item in a list
    36. push - insert an item at the front of a list
    37. quicksort, quicksort$ - sort a list, using QuickSort
    38. reduce, reduceRight - reduce a list to an object
    39. remove, remove$, operator - - remove an object from a list
    40. removeif, removeif$ - conditionally remove items
    41. reverse - reverse a list
    42. rotate$ - reorder members of a list
    43. sort, sort$ - sort a list
    44. subseq - subsequence of a list
    45. subtract, subtract$, - - subtract one list from another
    46. ToHash - convert to a Hash
    47. ToString - override string representation
    48. union - union of two lists
    49. uniq, uniq$ - remove duplicates from a list
  5. Compare functors
    1. CompareCar - compare list first elements
    2. CompareDesc - descending sort
    3. CompareList - compare lists
    4. CompareMap1 - map the first object in a comparison
    5. CompareMap2 - map both objects before comparing them
    6. CompareString - compare ToString() results
    7. CompareVar - compare Vars
    8. CompareVarAlpha - compare Vars as alphanumeric
    9. CompareVarDec - compare Vars as decimal
    10. CompareVarInt - compare Vars as integer
  6. Mapper functors
    1. abstract MapObject - map one object to another
      1. MapAssoc - map a key to its association in an alist
      2. MapDeep - recursively map all ls members
      3. MapIf - map objects using MapBoolean
      4. MapKey - create a key => value pair from a value
      5. MapVar - map objects to Var
        1. MapAlpha - map objects to VarAlpha
        2. MapDec - map objects to VarDec
        3. MapInt - map objects to VarInt
        4. MapReplace - apply Regex replacement
    2. abstract MapBoolean - map an object to a boolean
      1. MapMatches - map true if Regex matches
      2. MapNonNull - map true if not null
      3. MapNull - map true if null
  7. Reducer functors
    1. abstract Reducer - reduce two objects to one
    2. ReduceSum - add all Vars
    3. ReduceDifference - subtract all Vars
    4. ReduceProduct - multiply all Vars
    5. ReduceQuotient - divide all Vars

Explanation of symbols used

Words in italics indicate an instance of a class. The word corresponds to the class name, except where more than one instance is represented in the same statement. In that case a number (2, 3, etc.) is appended to the class name.

Words in normal typeface are to be taken literally (required punctuation, class name in a static reference, method name, etc.)

The symbol => is used to separate an expression (on the left) from its return value (on the right).

An ellipsis (...) indicates that the previous argument may be repeated any number of times. The description will indicate whether one instance is required.

Generally speaking, methods that end in "$" modify the receiver, while methods that don't end in "$" are free of side-effects. But that isn't always the case. The methods push and pop (as well as the properties car and cdr when set) modify the receiver -- but I have omitted the "$" because their traditional names adequately communicate their side-effects, I believe.

Member reference

constructors

ls = new ls()
ls = new ls(int)
Creates a new, empty list, optionally specifying initial capacity as int. The optional capacity merely provides a performance enhancement when the correct or usual capacity is known -- the list will be expanded as needed beyond this number.

methods append, append$, appendflat$, add$; operators +, |, &

ls.append(object) => ls2
ls + object => ls2

ls.append$(object) => ls
ls | object => ls

ls.add$(object) => ls
ls & object => ls

ls.appendflat$(object) => ls

The append method (and the + operator) adds an object to a list, returning a new list. if object is an ArrayList (or a derived class, such as another ls), then all of its members are added instead of the ArrayList itself.

The append$ method (and the | operator) modifies ls by adding the object in place, and returns the modified list. It also expands any Arraylist passed.

The add$ method (and the & operator) operates like append$, but ArrayLists are not expanded. This provides for composing nested lists.

The appendflat$ method operates like append$, but any ArrayList argument is completely flattened. Not only is the Arraylist replaced by its members, but any members of the ArrayList that are ArrayLists are recursively expanded.

In all of the above, if object is a primitive, it will be automatically boxed in a Var

.

Examples of list composition

ls.of(1) | 2 | "fred" | an_object | a_list

Creates a one-dimensional list from three primitives (which are boxed as Vars), an object, and the members of another list


    ls.of("1a") & "1b" &
    &     (ls.of("2a") &
    &           (ls.of("3a") & "3b"))
    

Creates a tree with three top nodes: "1a", "1b", and another list that contains two nodes: "2a" and another list that contains two nodes: "3a" and "3b". Note that the ampersands on the left side are Synergy/DE line-continuation characters.

Why didn't I use "<<" for append, and reserve "|" and "&" for union and intersection, respectively? Synergy/DE does not provide an override for "<<". I didn't want to use just "<" in case I add comparison operators later, and intersection and union seem like rare enough operations that requiring them to be spelled out should not be onerous.

property car

ls.car => object
ls.car = object
Property for referencing the first element of a list. Because this is a property, auto-boxing of primitives does not occur. In the first form, if the list is empty, ^null is returned. In the second form, if the list is empty, then object is added.

property cdr

ls.cdr => ls
ls.cdr = ls2
Property for referencing the second and following elements of a list. When retrieved, a new ls containing the second through last items is returned. When set, the second through last elements of the list are removed and replaced with the elements of ls2.

methods chop, chop$

ls.chop(int) => ls2
ls.chop$(int) => ls
Both of these methods truncate the list at the length specified by int (in other words, removing items from that index to the end). The chop method returns a truncated copy of the original list, leaving the original unmodified, while chop$ modifies and returns the original list.

methods compact, compact$

ls.compact() => ls2
ls.compact$() => ls
Both of these methods remove null elements from a list. The compact$ method modifies and returns the original list, while compact returns a modified shallow copy, leaving the original untouched.

method contains

ls.contains(object) => boolean
Returns true if object is a member of the list, otherwise false. This test uses IndexOf, which in turn invokes the Equals() method to compare objects. To determine whether a list is a subset of another list, see issubsetof and issupersetof.

method copy

ls.copy() => ls2
Returns a shallow copy of a list (members are copied by reference).

method countif

ls.countif(mapboolean) => int
Returns the count of the number of elements in the list that, when passed to mapboolean's test method, return true. See MapBoolean.

method deepcopy

ls.deepcopy() => ls2
Copies all members of all nested lists. Unlike copy, which copies all members by reference even if they are lists, deepcopy makes a copy of any member that is a list, recursively.

static method empty

ls.empty() => ls
Creates and returns a new empty list. This method is provided because the syntax new ls() is not valid in all contexts where the result of a method can be used instead.

override method Equals

ls.Equals(object) => boolean
Override of object.Equals() to specialize the comparison of an ls and any ArrayList. The two lists are considered equal if they have the same Count, and invoking Equals() on each of the members of ls returns true when passed the corresponding member of object (or both are ^null).

method find

ls.find(mapboolean) => object
Returns the first element of ls for which mapboolean.test() returns true. If no objects match, ^null is returned.

method findall

ls.findall(mapboolean) => ls2
Returns a list of all elements of ls for which mapboolean.test() returns true. If no objects match, an empty list is returned.

method flatten

ls.flatten() => ls2
Returns a copy of a list in which all members that are ArrayLists are recursively replaced by their members. The result is a flat list of all non-ArrayList members.

static method from

ls.from(arraylist) => ls
ls.from(hash) => ls
ls.from(array) => ls
ls.from(realarray) => ls   *** Synergy/DE 9.3 and above ***

Creates a new ls from arraylist, hash, or array. Members are copied by reference.

For hash, an alist will be created in which each element is a pair composed from the key value and associated object from the Hash. See keyfind.

For array, up to 3 dimensions are supported for dynamic object arays ([#,#,#]@class), and those dimensions will be preserved as lists within lists. Note that no automatic type conversions will occur. In particular, strings are not converted to VarAlpha. Use the map method to perform these conversions, if desired. For instance, to convert a multi-dimensioned array of strings to a list of lists of VarAlpha:

ls.from(array).map(new MapDeep(new MapAlpha()))

Real arrays of primitive types ([*]type) only work on Synergy/DE version 9.3 and above, due to a compiler bug (tr#30719). If you try to use real arrays with this method in Synergy/DE version 9.1* or even in the 9.2.1 beta, it will crash the Synergy/DE runtime. This method only supports real arrays of one dimension, because I got tired of fighting with the compiler. The primitive values will be boxed as Vars.

Note also that since arrays are 1-based while ArrayLists are 0-based, the indices of members in the resulting list will be one less than their indices in the original array. That goes for both array and realarray

method issubsetof

ls.issubsetof(ls2) => boolean
Returns true if every member of ls can be found in ls2, otherwise false.

method issupersetof

ls.issupersetof(arraylist) => boolean
Returns true if every member of arraylist can be found in ls, otherwise false.

method join

ls.join(string) => string2
Returns a string composed of the return value of the ToString() method of each non-null element in the list, separated by string.

method keyadd

ls.keyadd(object, object2) => ls
Adds object2 to the association for key object. If object or object2 are primitives, they will be boxed as Vars. Unlike method keyset, this method does not delete any previous association with the key, it merely adds another object to the sublist for the association. This allows for multiple objects associated with the same key, as in a multimap.. Use the method keygetl to retrieve all associations for a key as an ls.

method keydel

ls.keydel(object) => ls
Removes the entire first association in the list whose key matches object. See keyfind for details. If object is a primitive, it will be automatically boxed in a Var.

method keyfind

ls.keyfind(object) => ls2
Finds a member of an alist using object as a key. For each element of ls, if that element is also an ls with at least one member, object's Equal() method is invoked to test for a match against the first element of that ls. If it returns true, the ls is returned. If the key is a primitive, it is automatically boxed as a Var. This supports the alist construct in which elements of a list are themselves lists in which the first element is treated as a key. This implementation is a bit naive and underperforms for large arrays (O(n*(n/2)) to randomly access all elements). For a much faster version that is limited to alphanumeric keys and does not provide many of the features of ls, try Hash.

method keyget, property Indexer get

ls.keyget(object) => object2
ls[object] => object2
Gets the value object2 associated with a key object in an alist. If no such key exists in the alist, ^null is returned. If object is a primitive, it is automatically boxed as a Var, except for numeric types passed to the Indexer (in order to avoid hiding ArrayList.Indexer). If more than one value is associated with the key, they are returned in an ls.

method keygetl

ls.keygetl(object) => ls
Gets the list of values associated with key object in an alist. If object is primitive, it will be boxed in a Var. If the key is not found, an empty ls is returned.

method keyset, property Indexer set

ls.keyset(object, object2) => ls
ls[object] = object2
Sets the value object2 associated with a key object in an alist. If the alist already contains an association for the specified key, then that association sublist's cdr is replaced by object2. Otherwise, a new sublist is added to ls containing the pair object, object2. If either object is a primitive, it is automatically boxed as a Var, except for numeric types passed to the Indexer (in order to avoid hiding ArrayList.Indexer).

method intersection

ls.intersection(arraylist) => ls2
Returns a new list containing all of the members of the original list that are also found in arraylist (which can be another ls). Because of the implementation of ls.Equals(), elements that are instances of ls and contain the same members will be treated as identical.

property last

ls.last => object
ls.last = object
Accesses the last member of ls. If the list contains no elements, the get method returns ^null, while the set method adds an element.

static method of

ls.of(object) => ls
Creates a new single-element ls containing object. if object is a primitive, it will be automatically boxed in a Var.

macro make_pair

make_pair(object, object2) => ls
This macro provides an alternative syntax for creating a list containing two objects. If either object is primitive, it will be boxed as a Var. This macro is exactly equivalent to ls.of(object) & object2

methods map, map$

ls.map(mapobject) => ls2
ls.map$(mapobject) => ls
These methods map each object in the list to another object, which is the result of passing the original object to mapobject's map method. The ls method map produces a new list, while map$ replaces each item in the original list. See MapObject.

method mapnonull

ls.mapnonull(mapobject) => ls2
This method operates like map, except that any ^null that results from calling mapobject.map will not be included in the resulting list.

methods merge, merge$

ls.merge(arraylist, compare) => ls2
ls.merge$(arraylist, compare) => ls

Assumes that both lists are sorted, and returns a merged list. The two methods use different algorithms, with merge$ inserting items from arraylist into ls, while merge appends items from each list to the new ls2. Method mergesort uses the merge, which performs slightly better with large lists.

Comparisons between the members of the two lists are performed by calling the test method of compare. See Compare functors.

method mergesort

ls.mergesort(compare) => ls2
Sorts the list, using compare, and returns a new list (leaving ls unmodified). See Compare functors. MergeSort appears from testing to be faster than QuickSort when the list contains more than circa 100,000 elements. Therefore, sort uses a combination of the two, depending on the size of each segment.

method pop

ls.pop() => object
Removes and returns the first element of the list. If the list is empty, returns ^null.

method poplast

ls.pop() => object
Removes and returns the last element of the list. If the list is empty, returns ^null. There is no push_last method, because that functionality is already supplied by the methods add (ArrayList) and add$.

method push

ls.push(object) => ls
Inserts object at the front of the list, returning the modified list.

methods quicksort, quicksort$

ls.quicksort(compare) => ls2
ls.quicksort$(compare) => ls

Sorts the list, using compare. See Compare functors. Both methods use the in-place QuickSort algorithm, but quicksort copies the list first, while quicksort$ modifies ls. QuickSort appears from testing to be faster than MergeSort when the list contains fewer than circa 100,000 elements. Therefore, sort uses a combination of both, based on the size of each segment.

This QuickSort algorithm reverts to an Insertion sort when the number of elements is less than 5. When doing a QuickSort, the middle item is used as a pivot -- experimentation with optimizing the pivot value (median of 3, or pseudomedian of 9) yielded no improvements. The "collapse the walls" algorithm was adopted for speed, but note that this means the sort is not stable (i.e., the order of duplicates is not preserved).

methods reduce, reduceRight

ls.reduce(Reducer) => object
ls.reduce(Reducer, object2) => object
ls.reduceRight(Reducer) => object
ls.reduceRight(Reducer, object2) => object

These methods implement the equivalent of reduce, fold, inject, or accumulate in other languages. They iterate over the members of the list, invoking Reducer's reduce method, passing it the accumulator object and he list member. What Reducer returns becomes the new accumulator object, the final value of which is returned.

The methods reduce and reduceRight differ in the order in which members are processed. The reduce method goes lowest index to highest, while reduceRight does the reverse.

If object2 is passed, it is treated as an initial value, and the first call to Reducer will pass that as the accumulator. If object2 is not passed, then the first call to Reducer will pass the first (or last) member of the list as the accumulator, and will begin with the second member as the member argument.

If object2 is a primitive, it will automatically be boxed as a Var.

methods remove, remove$; operator -

ls.remove(object) => ls2
ls.remove$(object) => ls
ls - object => ls2
Removes all occurences of object from ls, returning either a new ls (in the case of remove and the operator -), or the modified receiver (in the case of remove$). If object is not a member of ls, no error occurs. if object is primitive, it will be boxed in a Var so that Var comparisons will apply. See subtract for a method to remove all elements of one list from another.

methods removeif, removeif$

ls.removeif(mapboolean) => ls2
ls.removeif$(mapboolean) => ls
Removes objects from a list that return true when passed to mapboolean's test method. See MapBoolean. The method removeif leaves ls unmodified, while removeif$ modifies and returns ls.

method reverse

ls.reverse() => ls2
Creates and returns a copy of the original list with the order of its members reversed.

method rotate$

ls.rotate$(int...) => ls
Swaps members of a list by index. At least one index is required. The element at the first specified index will be moved to the last specified index. The member at the second specified index (if any) will be moved to the first specified index, and so forth. Returns the modified list.

methods sort, sort$

ls.sort(compare) => ls2
ls.sort$(compare) => ls
Sorts a list, using compare. See Compare functors. The method sort$ uses QuickSort to sort the list in-place, while sort creates a sorted copy of the list. For sort, MergeSort is used for lists containing 100,000 elements or more, but when any segment within the sort contains fewer than 100,000 elements, QuickSort is used to sort that segment.

method subseq

ls.subseq(int) => ls2
ls.subseq(int, int2) => ls2
Returns a list containing the members of the original list beginning at the index specified by int, up to and including the index specified by int2. If int2 is omitted, the last element in the list is assumed.

methods subtract, subtract$; operator -

ls.subtract(arraylist) => ls2
ls.subtract$(arraylist) => ls
ls - arraylist => ls2
Removes all the elements of arraylist from ls. In the case of subtract and the operator -, the ls is unmodified and a new list is returned -- while subtract$ modifies and returns its receiver. If an element in arraylist does not occur in ls, no error occurs. See remove for removing objects from a list.

method ToHash

ls.ToHash() => hash
ls.ToHash(boolean) => hash

Creates a new Hash from this list. If boolean is passed, it specifies whether the new Hash has case-sensitive keys. If not passed, case-sensitivity is true by default.

Not all elements in a list may qualify for inclusion in the new Hash. To be included, they must conform to the model of an alist with a unique alphanumeric key for each object. In other words, only elements that are themselves an ls containing at least two elements where the first two elements are non-null will be considered. The first element's string representation will be used as the hash key, and the second element will be stored as the associated object.

override method ToString

ls.ToString() => string
Override of object.ToString() to specialize the string representation of lists. the list is represented as a "[" followed by the result of ToString() on each of its elements (separated by commas), followed by a closing "]". Null elements are represented as "^null".

methods union, union$

ls.union(arraylist) => ls2
ls.union$(arraylist) => ls
ls.union(object) => ls2
ls.union$(object) => ls
Returns a list containing all of the members of the original list and all of the members in arraylist (which can be another ls). If object is passed (i.e., a non-ArrayList object), it will be treated as a list of one object -- and if it is primitive it will be boxed as a Var. The union method returns a new list, while union$ modifies the receiver. Unlike append, any element found in both lists is not duplicated. You can therefore use this method to add objects uniquely, as in a set. Because of the implementation of ls.Equals(), elements that are instances of ls and contain the same members will be treated as identical.

methods uniq, uniq$

ls.uniq() => ls2
ls.uniq$() => ls
Both of these methods remove duplicates from a list (based on the element's Equals method). The uniq method returns a uniq'd copy of the list, while uniq$ modifies and returns the original list.

Compare functors

Introduction

The abstract class Compare provides a pattern for functors used in comparisons. It's a poor man's excuse for lambdas, and about the only way to provide a lazy callback that can handle objects in Synergy/DE.

Derived classes must implement one method: test, which takes two object arguments and returns an integer. If the first object is greater than the second, return 1. If equal, return 0, If less than, return -1. The method must be able to handle null objects.

Derived classes may implement other members as needed. For instance, a number of the provided classes (detailed below) implement constructors that take parameters to control their behavior.

Some Compare classes take a Compare as an argument. These are intended to modify the comparison operation in some way. For instance, to compare objects as lists of strings in descending order, you could create a combined functor like: new CompareDesc(new CompareList(new CompareString())). CompareDesc will reverse the sense of the return value from CompareList, which will call CompareString to compare each member of the lists contained within the list. A good combination to use for sorting an associative list by key value (if the keys are strings) would be new CompareCar(new CompareVarAlpha()) .

Compare functors also provide overloads for the comparison operators (==, !=, >, <, >=, and <=), each of which produce a MapBoolean object that performs the specified lazy comparison against the right-hand term (MapCompareEqual, MapCompareNotEqual, MapCompareGreaterThan, MapCompareLessThan, MapCompareGreaterThanOrEqual, MapCompareLessThanOrEqual). See MapBoolean. If the right-hand term is primitive, it will be automatically boxed as a Var. Thus, for example, to create a lazy evaluation functor for testing Vars as greater than 5, use new CompareVar() > 5, which produces a MapBoolean that performs that test against the object passed to its test method.

The following derived classes are provided:

CompareCar

new CompareCar(compare)

If either of the objects is a list, its first element will be used -- otherwise the object itself. If that first element is a list, its first element will be used, and so on recursively until a non-list is encountered. Then the result returned from invoking compare's test method for those two objects will be returned.

This Comparer is useful for sorting associative lists by key. An associative list (or alist) is one in which each element is itself a list, comprised of a key and data. See keyfind.

CompareDesc

new CompareDesc(compare)
Reverses the order provided by compare.

CompareList

new CompareList(compare)
This comparer treats each object as a list. if either of the objects is not a list, then it is automatically wrapped in a list. Each list is then compared (using compare) element by element until not equal, or the end of a list is reached. If one of the lists then contains more elements, it is treated as greater -- if the same, they're equal.

CompareMap1

new CompareMap1(mapobject, compare)
Uses mapobject to map only the first of the two objects to be compared before passing both to compare's test method. This comparer should not be used in a sort, but it may be useful in other contexts, such as the ls methods countif or removeif.

CompareMap2

new CompareMap2(mapobject, compare)
Uses mapobject to map both of the objects to be compared before passing them to compare's test method. This comparer should be used when mapping objects for sorting.

CompareString

new CompareString()
new CompareString(boolean, boolean2)
TestNatural(string, string2) => int

Compares the result of ToString() on both objects. ^null is considered equal to "".

When the constructor is invoked without arguments, defaults to case-insensitive, natural order. If called with arguments, boolean is true for case-sensitive, boolean2 is true for natural order or false for alphanumeric order.

This class also provides the static method TestNatural that compares two strings according to natural order rules.

CompareVar

new CompareVar()
Compares Var objects using Var's built-in comparisons. Non-Vars are treated as greater than Vars, and their order relative to each other is undefined.

CompareVarAlpha

new CompareVarAlpha()
Compares Var objects, casting them to alphanumeric. Non-Vars are treated as greater than Vars, and their order relative to each other is undefined.

CompareVarDec

new CompareVarDec()
Compares Var objects, casting them to decimal. Non-Vars are treated as greater than Vars, and their order relative to each other is undefined.

CompareVarInt

new CompareVarInt()
Compares Var objects, casting them to integer. Non-Vars are treated as greater than Vars, and their order relative to each other is undefined.

Mapper functors

Introduction

Mappers are used to map one object to another object or value. Currently there are two types of mappers, which correspond to the two abstract classes MapObject and MapBoolean.

MapObject

MapObject maps one object to another. Derived classes must override method map, which takes an object as argument and returns an object. The following derived classes may provide what you need:

MapAssoc

new MapAssoc(ls)
Maps objects as keys in an alist (ls), returning their associated object.

MapDeep

new MapDeep(mapobject)

Recursively maps all sublists using mapobject. For each object passed to this mapper's map method, if that object is not an ls, the result is the result of mapping that object using mapobject's map method. If the object is an ls, then the result is a new ls containing the results of mapping each of the original members of that sublist using MapDeep and mapobject.

This mapper if useful for mapping only the leaf nodes in a tree, where branches are represented by lists within lists

.

MapIf

new MapIf(mapboolean, object)
new MapIf(mapboolean, object, object2)
Maps objects to object or object2, depending on the result of passing each incoming object to mapboolean's map method: if true, object, else object2. If object2 is not given, then the original object is returned instead. See MapBoolean. If the resulting object is also a MapObject, the incoming object is passed to its map method to produce the final result. Thus, nested ifs and elses can be achieved, as well as conditional mapping functors per object.

MapKey

new MapKey(mapobject)
Creates key => value pairs from objects, using mapobject to produce the key. The resulting object is an ls containing the key and the original object. Thus, passing a MapKey to the ls methods map or map$ produces an alist.

MapVar

new MapVar()

Treats each object as a Var. Non-Vars are returned as-is. This class is most useful for its derived classes and the operators it provides, which create derived class instances to perform lazy operations on each mapped object.

For instance, new MapVar() + 12 creates a MapVarAdd object (derived from MapVar) that will add 12 to each object being mapped. MapVar provides operations for addition, subtraction, multiplication, division, and unary negation.

If either operand in an expression is a MapVar, it will be passed the object to map until a non-MapVar is returned. Thus it is possible to substitute the object being mapped at multiple points in a mathematical operation. For instance, integer(100) - integer(100) / new MapInt() * new MapInt() provides a poor man's modulo function (100 mod x, where x is the object being mapped). Of course, a simpler approach is to use MapVar's modulo method: MapVar.modulo(100, new MapInt())

Some derived classes of MapVar may be instantiated directly:

MapAlpha

new MapAlpha()
new MapAlpha(case)
Maps objects to their ToString() representation, optionally manipulating case. Case is an enumeration of Case.NoChange (the default), Case.Upper, or Case.Lower. The resulting string is boxed in a Var. Null objects are mapped to "".

MapDec

new MapDec()
Maps objects to a decimal Var (VarDec). If the incoming object is a Var, it is merely cast as decimal and re-boxed. Otherwise, the object's ToString() representation is boxed as a VarAlpha and then cast as decimal and re-boxed -- resulting in an alpha to decimal conversion, with any non-decimal string returning 0. Null objects are also mapped to 0.

MapInt

new MapInt()
Maps objects to an integer Var (VarInt). If the incoming object is a Var, it is merely cast as integer and re-boxed. Otherwise, the object's ToString() representation is boxed as a VarAlpha and then cast as integer and re-boxed -- resulting in an alpha to integer conversion, with any non-decimal string returning 0. Null objects are also mapped to 0.

MapReplace

new MapReplace(regex, a)
Performs Regular Expression replacement on the string representation of objects mapped, resulting in a VarAlpha. The matching portion of the string will be replaced by a, which may contain escaped references to portions of the string such as sub-expression matches. See the Regex documentation for the replace method.

MapBoolean

MapBoolean maps an object to a boolean value. Derived classes must override method test, which takes an object as argument and returns a boolean.

MapBoolean includes operator overloads for .and. (&&), .or. (||) and .xor. comparisons against other MapBooleans, each yielding a new MapBoolean that combines the two lazy tests (MapAnd, MapOr, and MapXor, respectively). Synergy/DE optimizations apply -- that is, if the first operation in an .and. yields false, the second operation will not be tested, etc. Grouping with parentheses works as expected. An overload for the .not. operator (!) is also provided, which yields a MapBoolean object that reverses the result of its argument (MapNot).

Most of the provided derived classes are instantiated through the use of operators on either the MapBoolean or Compare classes. But you may create your own derived classes to perform other tests.

The following additional derived classes are provided:

MapMatches

new MapMatches(regex)
Maps objects to true if their string representation matches the Regular Expression regex. See the Regex documentation under the match method.

MapNonNull

new MapNonNull()
Maps objects to true if they're not equal to ^null, otherwise false.

MapNull

new MapNull()
Maps objects to true if they're equal to ^null, otherwise false.

Reducer functors

Reducers are passed to ls's reduce and reduceRight methods to provide the reduction algorithm to employ.

abstract Reducer

All reducers must be derived from this class, and must override the method reduce, which has the following signature:

Reducer.reduce(object, object2) => object3

where:

  • object is the accumulator object. On the first call, this will be either the initial value passed to ls.reduce/reduceRight, or the first/last element of the list if no initial value was passed. On subsequent calls, it will be the result of the previous call.
  • object2 is the next member of the list.
  • object3 is the new value for the accumulator.

You may derive your own reducer class to implement whatever reduction you need, but the following classes are provided.

ReduceSum

new ReduceSum()
Adds all members that are Vars, according to Var rules for addition, and returns a Var. The initial value, if supplied, must also be a Var or it will be ignored.

ReduceDifference

new ReduceDifference()
Subtracts all members that are Vars, according to Var rules for subtraction, and returns a Var. The initial value, if supplied, must also be a Var or it will be ignored. On each iteration, the next element is subtracted from the accumulator.

ReduceProduct

new ReduceProduct()
Multiplies all members that are Vars, according to Var rules for multiplication, and returns a Var. The initial value, if supplied, must also be a Var or it will be ignored.

ReduceQuotient

new ReduceQuotient()
Divides all members that are Vars, according to Var rules for division, and returns a Var. The initial value, if supplied, must also be a Var or it will be ignored. On each iteration, the accumulator is divided by the next member.