Contents Array Adapters Function Objects

Algorithms

List of Algorithms by Category
Applying
Copying
Counting
Finding
Filtering
Replacing
Reversing
Sorting
Transforming
Applying an Algorithm to a Sub-Range of a Container

One of JGL's primary strengths is its comprehensive set of reusable algorithms that can be applied to a wide variety of data structures, including JGL containers, JDK containers, and native Java arrays. Because JGL algorithms are stand-alone and are not part of any JGL container, you can add new algorithms to JGL without changing any of the existing code. We hope that users of JGL will send new algorithms to ObjectSpace so that they can be incorporated into subsequent releases of JGL. Significant contributions will always be acknowledged in our documentation.

All JGL algorithms are categorized and packaged as public static methods of a class that represents the category. For example, the remove(), removeIf(), removeCopy(), and removeCopyIf() algorithms are all public static methods of the Removing class.

The next section contains a list of all the JGL algorithm classes and methods. Subsequent chapters contain examples of several common algorithms at work.


List of Algorithms by Category

This section lists all of the JGL algorithms by class, together with a brief synopsis. Each algorithm is implemented as a public static method of its associated class - you cannot create instances of any algorithm class. For detailed information about a particular algorithm, consult the online class catalog.

Applying
forEachapply a function to every item in a range
injectiteratively apply a binary function to every item in a range

Comparing
equalcheck that two sequences match
lexicographicalComparelexicographically compare two sequences
medianreturn the median of three values
mismatchsearch two sequences for a mismatched item

Copying
copycopy a range of items to another area
copyBackwardcopy a range of items backwards to another area

Counting
accumulatesum the values in a range
adjacentDifferencecalculate and sum the difference between adjacent values
countcount items in a range that match a value
countIfcount items in a range that satisfy a predicate

Filling
fillset every item in a range to a particular value
fillNset n items to a particular value

Filtering
rejectreturn all values that do not satisfy a predicate
selectreturn all values that satisfy a predicate
uniquecollapse all consecutive values in a sequence
uniqueCopycopy a sequence, collapsing consecutive values

Finding
adjacentFindlocate consecutive sequence in a range
detectreturn first item that satisfies a predicate
everyreturn true if every item in a range satisfies a predicate
findlocate an item in a sequence
findIflocate an item that satisfies a predicate in a range
somereturn true if at least one item in a range satisfies a predicate

Heap
makeHeapmake a sequence into a heap
popHeappop the top value from a heap
pushHeapplace the last element into a heap
sortHeapsort a heap

MinMax
minElementreturn the minimum item within a range
maxElementreturn the maximum item within a range

Permuting
nextPermutationchange sequence to next lexicographic permutation
prevPermutationchange sequence to previous lexicographic permutation

Printing
printprints a sequence to standard output
printlnprints a sequence to standard output followed by a newline
toStringreturns a description of a sequence

Removing
removeremove all matching items from a sequence
removeCopycopy a sequence, removing all matching items
removeCopyIfcopy sequence, removing all that satisfy predicate
removeIfremove items that satisfy predicate from sequence

Replacing
replacereplace specified value in a sequence with another
replaceCopycopy sequence, replacing matching values
replaceCopyIfcopy sequence, replacing values that satisfy predicate
replaceIfreplace specified values that satisfy a predicate

Reversing
reversereverse the items in a sequence
reverseCopycreate a reversed copy of a sequence

Rotating
rotaterotate a sequence by n positions
rotateCopycopy a sequence, rotating it by n positions

SetOperations
includessearch for one sequence in another sequence
setDifferencecreate set of elements in 1st sequence that are not in 2nd
setIntersectioncreate set of elements that are in both sequences
setSymmetricDifferencecreate set of elements that not in both sequences
setUnioncreate set of elements that are in either sequence

Shuffling
randomShufflerandomize sequence using random shuffles

Sorting
sortsort a sequence

Swapping
iterSwapswap the values indicated by two iterators
swapRangesswap two ranges of items

Transforming
collectreturn result of applying a function to every item in a range
transformtransform one sequence into another


Applying

The Applying class has a couple of algorithms for applying a function to every element of a container. forEach() applies a unary function to every element of a container. inject() calculates an initial result by calling a binary function with the initial value as the first parameter and the first element as the second parameter. It then applies the function to the remaining elements, using the previous result as the first parameter and the next element as the second parameter. The last result is then returned. For more information about unary and binary functions, refer to the Function Objects chapter. The following example illustrates both of the applying algorithms.



Example Algorithms1.java

// Copyright(c) 1996,1997 ObjectSpace, Inc.
import COM.objectspace.jgl.*;

public class Algorithms1
  {
  public static void main( String[] args )
    {
    Array array1 = new Array();
    array1.add( "cat" );
    array1.add( "monkey" );
    array1.add( "goat" );
    Applying.forEach( array1, new PrintFunction() );

    SList list = new SList();
    list.add( new Integer( 3 ) );
    list.add( new Integer( 7 ) );
    list.add( new Integer( 4 ) );
    Integer total = (Integer) Applying.inject( list, new Integer( 0 ), new PlusNumber() );
    System.out.println( "list = " + list + ", total = " + total );
    }
  }

class PrintFunction implements UnaryFunction
  {
  public Object execute( Object object )
    {
    System.out.println( "PRINT " + object );
    return null; // Not used.
    }
  }

Output


PRINT cat
PRINT monkey
PRINT goat
list = SList( 3, 7, 4 ), total = 14


Copying

The Copying class contains a variety of copying algorithms for adding the contents of one container to another container. Behind the scenes, the algorithms use the destination's add() method to perform the copy. The following example uses container adapters to copy the contents of a native Java array of ints into a JDK Vector.



Example Algorithms2.java

// Copyright(c) 1996,1997 ObjectSpace, Inc.
import COM.objectspace.jgl.*;
import java.util.Vector;

public class Algorithms2
  {
  public static void main( String[] args )
    {
    int ints[] = { 2, 6, 3, 7 };
    Vector vector = new Vector();
    vector.addElement( new Integer( 1 ) );
    vector.addElement( new Integer( 4 ) );

    // Create container adapters.
    IntArray intArray = new IntArray( ints );
    VectorArray vectorArray = new VectorArray( vector );

    System.out.println( "vector before copying = " + vector );
    Copying.copy( intArray, vectorArray );
    System.out.println( "vector after copying = " + vector );
    }
  }

Output


vector before copying = [1, 4]
vector after copying = [1, 4, 2, 6, 3, 7]


Counting

The Counting class has several algorithms for involving counting the elements in a container that either match a particular value or satisfy a specified unary predicate. For more information about predicates, refer to the Function Objects chapter. The following example illustrates the most common varieties of the counting algorithms.



Example Algorithms3.java

// Copyright(c) 1996,1997 ObjectSpace, Inc.
import COM.objectspace.jgl.*;

public class Algorithms3
  {
  public static void main( String[] args )
    {
    SList list = new SList();
    list.add( new Integer( -1 ) );
    list.add( new Integer( 1 ) );
    list.add( new Integer( -2 ) );
    list.add( new Integer( 1 ) );
    list.add( new Integer( -3 ) );
    System.out.println( "list = " + list );

    Object value = new Integer( 1 );
    int n1 = Counting.count( list, value );
    System.out.println( "Occurences of " + value + " = " + n1 );

    int n2 = Counting.countIf( list, new NegativeNumber() );
    System.out.println( "Occurences of a negative = " + n2 );
    }
  }

Output


list = SList( -1, 1, -2, 1, -3 )
Occurences of 1 = 2
Occurences of a negative = 3


Finding

The Finding class has several algorithms for locating elements in a container that either match a particular value or satisfy a specified unary predicate. For example, detect() returns the first object that satisfies a unary predicate, and some() returns true if at least one object in the container satisfies a unary predicate. For more information about predicates, refer to the Function Objects chapter. The following example illustrates two of the finding algorithms.



Example Algorithms4.java

// Copyright(c) 1996,1997 ObjectSpace, Inc.
import COM.objectspace.jgl.*;

public class Algorithms4
  {
  public static void main( String[] args )
    {
    int ints[] = { 3, 7, 8, 2, -5, 8, 9, -2 };
    IntArray array = new IntArray( ints );
    System.out.println( "array = " + array );

    Integer negative = (Integer) Finding.detect( array, new NegativeNumber() );
    System.out.println( "first negative = " + negative );

    boolean some = Finding.some( array, new NegativeNumber() );
    System.out.println( "some items are negative = " + some );
    }
  }

Output


array = int[]( 3, 7, 8, 2, -5, 8, 9, -2 )
first negative = -5
some items are negative = true


Filtering

The Filtering class has several algorithms for creating a copy of a sequence whilst performing a filtering operation. For example, select() and reject() return a copy of a sequence that only contains the elements that do/don't satisfy a predicate, respectively. For more information about predicates, refer to the Function Objects chapter. The following example illustrates a couple of the filtering algorithms.



Example Algorithms5.java

// Copyright(c) 1996,1997 ObjectSpace, Inc.
import COM.objectspace.jgl.*;

public class Algorithms5
  {
  public static void main( String[] args )
    {
    Array array1 = new Array();
    array1.add( "cat" );
    array1.add( "monkey" );
    array1.add( "goat" );
    array1.add( "elephant" );
    System.out.println( "array1 = " + array1 );

    // Predicate that returns true if a string is greater than 4 characters long.
    UnaryPredicate predicate = new UnaryComposePredicate
      ( 
      new BindSecondPredicate( new GreaterNumber(), new Integer( 4 ) ), 
      new LengthString() 
      );

    Array array2 = (Array) Filtering.select( array1, predicate );
    System.out.println( "strings with length > 4 = " + array2 );

    Array array3 = (Array) Filtering.reject( array1, predicate );
    System.out.println( "strings with length <= 4 = " + array3 );
    }
  }

Output


array1 = Array( cat, monkey, goat, elephant )
strings with length > 4 = Array( monkey, elephant )
strings with length <= 4 = Array( cat, goat )


Replacing

The Replacing class contains generic algorithms for replacing objects that have a particular value or that satisfy a particular unary predicate. There are versions of the algorithm that modify the source container and others that copy the result into a separate container. The following example demonstrates two of these variations.



Example Algorithms6.java

// Copyright(c) 1996,1997 ObjectSpace, Inc.
import COM.objectspace.jgl.*;

public class Algorithms6
  {
  public static void main( String[] args )
    {
    DList list = new DList();
    list.add( new Integer( -1 ) );
    list.add( new Integer( 1 ) );
    list.add( new Integer( -2 ) );
    list.add( new Integer( 1 ) );
    list.add( new Integer( -3 ) );
    System.out.println( "list = " + list );

    Object oldValue = new Integer( 1 );
    Object newValue = new Integer( 4 );
    int n1 = Replacing.replace( list, oldValue, newValue );
    System.out.println( "after 1 -> 4, list = " + list );

    Array array = new Array();
    UnaryPredicate predicate = new NegativeNumber();
    newValue = new Integer( 0 );
    Replacing.replaceCopyIf( list, array, predicate, newValue );
    System.out.println( "list = " + list );
    System.out.println( "array = " + array );
    }
  }

Output


list = DList( -1, 1, -2, 1, -3 )
after 1 -> 4, list = DList( -1, 4, -2, 4, -3 )
list = DList( -1, 4, -2, 4, -3 )
array = Array( 0, 4, 0, 4, 0 )


Reversing

The Reversing class contains algorithms for reversing the contents of a container, as demonstrated by the following example.



Example Algorithms7.java

// Copyright(c) 1996,1997 ObjectSpace, Inc.
import COM.objectspace.jgl.*;

public class Algorithms7
  {
  public static void main( String[] args )
    {
    Deque deque = new Deque();
    deque.add( "Batman" );
    deque.add( "Superman" );
    deque.add( "Phantom" );
    deque.add( "Spider-Man" );
    System.out.println( "before reverse = " + deque );
    Reversing.reverse( deque );
    System.out.println( "after reverse = " + deque );
    }
  }

Output


before reverse = Deque( Batman, Superman, Phantom, Spider-Man )
after reverse = Deque( Spider-Man, Phantom, Superman, Batman )


Sorting

The Sorting class contains a highly efficient quicksort-based algorithm for sorting any Sequence. By default, elements are sorted in increasing order of hash value. This default behavior works well for sorting Integer objects, since their hash value is equal to their actual integer value. To change this default behavior, supply the sort algorithm with a binary predicate object. An object A will be placed to the left of an object B if the predicate object returns true when executed with A as the first operand and B as the second operand. For more information about predicates, refer to the chapter called Function Objects. The following example illustrates both uses of the sorting algorithm.



Example Algorithms8.java

// Copyright(c) 1996,1997 ObjectSpace, Inc.
import COM.objectspace.jgl.*;

public class Algorithms8
  {
  public static void main( String[] args )
    {
    Array array = new Array();
    array.add( new Integer( 3 ) );
    array.add( new Integer( -2 ) );
    array.add( new Integer( 4 ) );
    array.add( new Integer( -5 ) );
    System.out.println( "unsorted array = " + array );
    Sorting.sort( array );
    System.out.println( "sorted array = " + array );

    Deque deque = new Deque();
    deque.add( "triangle" );
    deque.add( "square" );
    deque.add( "pentagon" );
    deque.add( "hexagon" );
    System.out.println( "unsorted deque = " + deque );
    Sorting.sort( deque, new LessString() );
    System.out.println( "sorted deque = " + deque );
    }
  }

Output


unsorted array = Array( 3, -2, 4, -5 )
sorted array = Array( -5, -2, 3, 4 )
unsorted deque = Deque( triangle, square, pentagon, hexagon )
sorted deque = Deque( hexagon, pentagon, square, triangle )


Transforming

The Transforming class contains a couple of algorithms for replacing every element of a container with a transformed version of itself. The transformation is specified with a unary function object. It also contains an algorithm for applying a binary function in a pair-wise fashion to every element in two containers and storing the results into a third container. For more information about function objects, consult the Function Objects chapter. The following example illustrates these algorithms.



Example Algorithms9.java

// Copyright(c) 1996,1997 ObjectSpace, Inc.
import COM.objectspace.jgl.*;

public class Algorithms9
  {
  public static void main( String[] args )
    {
    int ints1[] = { 1, 3, 5, 2 };
    Array array = new Array();
    IntArray intArray1 = new IntArray( ints1 );
    UnaryFunction function = new NegateNumber();
    Transforming.transform( intArray1, array, function );
    System.out.println( "ints1 = " + intArray1 );
    System.out.println( "array = " + array );
    System.out.println();

    int ints2[] = { 2, 4, 2, 3 };
    int ints3[] = { 3, 6, 2, 1 };
    SList list = new SList();
    IntArray intArray2 = new IntArray( ints2 );
    IntArray intArray3 = new IntArray( ints3 );
    BinaryFunction function2 = new TimesNumber();
    Transforming.transform( intArray2, intArray3, list, function2 );
    System.out.println( "ints2 = " + intArray2 );
    System.out.println( "ints3 = " + intArray3 );
    System.out.println( "list = " + list );
    System.out.println();

    Array array1 = new Array();
    array1.add( "cat" );
    array1.add( "monkey" );
    array1.add( "goat" );
    System.out.println( "array1 = " + array1 );
    Array array2 = (Array) Transforming.collect( array1, new LengthString() );
    System.out.println( "array2 = " + array2 );
    }
  }

Output


ints1 = int[]( 1, 3, 5, 2 )
array = Array( -1, -3, -5, -2 )

ints2 = int[]( 2, 4, 2, 3 )
ints3 = int[]( 3, 6, 2, 1 )
list = SList( 6, 24, 4, 3 )

array1 = Array( cat, monkey, goat )
array2 = Array( 3, 6, 4 )


Applying an Algorithm to a Sub-Range of a Container

All of the algorithm examples in this section apply an algorithm to an entire container. If you wish you apply an algorithm to a sub-range of a container, you must take advantage of the JGL iterators. These are described fully in the Iterators chapter.

Contents Array Adapters Function Objects