Differences between revisions 4 and 5
| Deletions are marked like this. | Additions are marked like this. |
| Line 197: | Line 197: |
| ||'''Sample Expression'''||`#f = :[ @@floor(#this.l / 2) == @@floor(#this.r / 2) ], #ENV.unique( { 0,1,2,3,4,5 } )`|| | ||'''Sample Expression'''||`#f = :[ @@floor(#this.l / 2) == @@floor(#this.r / 2) ], #ENV.unique( { 0,1,2,3,4,5 }, #f )`|| |
Report Utility Functions
When defining the data set in a report, the columns are specified using OGNL expressions. While the OGNL language makes it very easy to navigate the graph of objects inside the Web-CAT data store, there are some other tasks, such as iteration, that require a non-trivial amount of work to write in OGNL alone. Therefore, we have provided a set of utility functions that can be called from within OGNL expressions to greatly simplify some common tasks.
These utility functions are provided as members of the global #ENV variable that is available to any OGNL expression in a report. To call one of these functions, simply use the standard notation: #ENV.functionName(arguments...).
Many of the utility functions take OGNL lambda expressions as arguments, to operate on the elements in a collection. To simplify the documentation below, these lambda expressions will be categorized as one of the types below:
UnaryOp: an expression that takes a single argument, denoted by #this. The return type and value are arbitrary.
BinaryOp: an expression that takes two arguments, denoted by #this.l and #this.r (that is, the left- and right-hand sides). The return type and value are arbitrary.
UnaryPredicate: an expression that takes a single argument, denoted by #this and has a Boolean return type.
BinaryPredicate: an expression that takes two arguments, denoted by #this.l and #this.r, and has a Boolean return type.
An important note: Due to the way OGNL parses expressions, a lambda expression cannot be included directly inside the function call; it must be stored in a variable first. In other words,
#ENV.accumulate( {1,2,3}, :[ #this.l + #this.r ] )
will not work as expected. The above expression must be rewritten as follows:
#f = :[ #this.l + #this.r ], #ENV.accumulate( {1,2,3}, #f )
Common OGNL Idioms
Many of the functions described below are modeled after the STL algorithms found in C++. Two common ones, fill and generate, are left out because they are already available through standard OGNL expressions.
To create a list containing n copies of a value, as fill would do, you can "project" across a number: (n).{ value }. For example, (5).{ 'test' } would return the list { 'test', 'test', 'test', 'test', 'test' }.
The generate algorithm can be written in the same way, by using an expression instead of a constant value in the projection. For example, to generate a list of five random numbers, one could use (5).{ @@random() }.
Available Functions
- accumulate: compute the sum of the elements in a list
- adjacentDifference: compute the adjacent differences of the elements in a list
- countIf: count the number of elements in a list that satisfy a condition
- forEach: evaluate an expression for each element in a list
- innerProduct: compute the scalar inner product of two lists
- joinLists: append two or more lists together
- joinMaps: merge the keys and values of two or more maps
- partialSum: compute the partial sums of the elements in a list
- range: create a list containing the integers in a range
- randomSample: randomly sample elements from a list
- randomShuffle: randomly shuffle elements in a list
- reverse: reverse the contents of a list
- unique: remove consecutive duplicate items in a list
accumulate
Signature |
Object accumulate( List list ) |
Description |
Returns the sum of the elements in list. Addition is performed with an initial value of zero (or the empty string in the case of strings) using the OGNL + (plus) operator and the results will conform to any such type conversions that may take place. |
Sample Expression |
#ENV.accumulate( {1,2,3,4,5} ) |
Sample Result |
15 |
Sample Expression |
#ENV.accumulate( {'a','b','c','d','e'} ) |
Sample Result |
'abcde' |
Version |
Requires Reporter x.y.z or higher. |
Signature |
Object accumulate( List list, Object initial, BinaryOp binOp ) |
Description |
Returns the generalized sum of the elements in list. Addition is performed with an initial value of initial using the specified binOp expression; #this.l is the sum computed thus far, and #this.r is the next item in the list to be added. |
Sample Expression |
#f = :[ #this.l * #this.r ], #ENV.accumulate( {1,2,3,4,5}, 1, #f ) |
Sample Result |
120 |
Version |
Requires Reporter x.y.z or higher. |
adjacentDifference
Signature |
List adjacentDifference( List list ) |
Description |
Returns a list containing the adjacent differences of the elements in list. In other words, the (i+1)st element in the result is the difference between the (i+1)st element and the ith element in list (and the 0th elements are the same). Subtraction is performed using the OGNL – (minus) operator and the results will conform to any such type conversions that may take place. |
Sample Expression |
#ENV.adjacentDifference( {1,2,8,10,20} ) |
Sample Result |
{ 1,1,6,2,10 } |
Version |
Requires Reporter x.y.z or higher. |
Signature |
List adjacentDifference( List list, BinaryOp binOp ) |
Description |
Returns a list containing the adjacent differences of the elements in list. In other words, the (i+1)st element in the result is the difference between the (i+1)st element and the ith element in list (and the 0th elements are the same). Subtraction is performed using the specified binOp expression; #this.l is the ith element in list and #this.r is the (i+1)st. |
Sample Expression |
#f = :[ #this.r / #this.l ], #ENV.partialSum( {1,2,8,64,256}, #f ) |
Sample Result |
{ 1,2,4,8,4 } |
Version |
Requires Reporter x.y.z or higher. |
countIf
Signature |
int countIf( List list, UnaryPredicate predicate ) |
Description |
Returns the number of elements in list that satisfy predicate; that is, for which predicate returns true. |
Sample Expression |
#f = :[ #this % 2 == 0 ], #ENV.countIf( {1,2,3,4,5}, #f ) |
Sample Result |
2 |
Version |
Requires Reporter x.y.z or higher. |
forEach
Signature |
void forEach( List list, UnaryOp operation ) |
Description |
Iterates over the elements in list, evaluating the lambda expression operation on each element. |
Sample Expression |
#x = 0, #f = :[ #x = #x + #this ], #ENV.forEach( {1,2,3}, #f ), #x |
Sample Result |
6 |
Version |
Requires Reporter x.y.z or higher. |
innerProduct
Signature |
Number innerProduct( List list1, List list2 ) |
Description |
Returns the inner product of list1 and list2. Elements are pairwise-multiplied with the OGNL * (multiply) operator and these products are accumulated with the OGNL + (plus) operator, so the result will conform to any type conversions that may occur there. The lists should be the same length. |
Sample Expression |
#ENV.innerProduct( {1,2,3}, {5,2,-2} ) |
Sample Result |
3 |
Version |
Requires Reporter x.y.z or higher. |
Signature |
Number innerProduct( List list1, List list2, Number initial ) |
Description |
Same as above, but uses initial as the initial value for the accumulation instead of zero. |
Sample Expression |
#ENV.innerProduct( {1,2,3}, {5,2,-2}, 5 ) |
Sample Result |
8 |
Version |
Requires Reporter x.y.z or higher. |
Signature |
Object innerProduct( List list1, List list2, Object initial, BinaryOp addOp, BinaryOp multOp ) |
Description |
Returns the inner product of list1 and list2. Elements are pairwise-multiplied with multOp and these products are accumulated with addOp (with an initial value of initial for the accumulation). |
Version |
Requires Reporter x.y.z or higher. |
joinLists
Signature |
List joinLists( List list1, List list2 ) |
Description |
Returns a new list containing the elements in list1 followed by the elements in list2. |
Sample Expression |
#l1 = { 1,2,3 }, #l2 = { 2,3,4 }, #ENV.joinLists(#l1, #l2) |
Sample Result |
{ 1,2,3,2,3,4 } |
Version |
Requires Reporter x.y.z or higher. |
Signature |
List joinLists( List<List> listOfLists ) |
Description |
A generalized version that returns a new list containing the elements of each of the lists in listOfLists, in the order they are passed. |
Sample Expression |
#l1 = { 1,2 }, #l2 = #{ 3,4 }, #l3 = #{ 1,4 }, #ENV.joinLists( { #l1, #l2, #l3 } ) |
Sample Result |
{ 1,2,3,4,1,4 } |
Version |
Requires Reporter x.y.z or higher. |
joinMaps
Signature |
Map joinMaps( Map map1, Map map2 ) |
Description |
Returns a new map containing the keys and values of the two specified maps. In the event that a key exists in both map1 and map2, the value in map2 will be used. |
Sample Expression |
#m1 = #{ 'a': 1 }, #m2 = #{ 'b': 2 }, #ENV.joinMaps(#m1, #m2) |
Sample Result |
#{ 'a': 1, 'b': 2 } |
Version |
Requires Reporter x.y.z or higher. |
Signature |
Map joinMaps( List<Map> listOfMaps ) |
Description |
A generalized version that returns a new map containing the keys and values from each map in the specified list of maps. In the event that a key exists in multiple maps, the values in the maps later in the list are used. |
Sample Expression |
#m1 = #{ 'a': 1 }, #m2 = #{ 'b': 2 }, #m3 = #{ 'c': 3 }, #ENV.joinMaps( { #m1, #m2, #m3 } ) |
Sample Result |
#{ 'a': 1, 'b': 2, 'c': 3 } |
Version |
Requires Reporter x.y.z or higher. |
partialSum
Signature |
List partialSum( List list ) |
Description |
Returns a list containing the partial sums of the elements in list. In other words, the ith element in the result is the sum of the 0th through ith elements in list. Addition is performed using the OGNL + (plus) operator and the results will conform to any such type conversions that may take place. |
Sample Expression |
#ENV.partialSum( {1,2,3,4,5} ) |
Sample Result |
{ 1,3,6,10,15 } |
Sample Expression |
#ENV.partialSum( {'a','b','c','d','e'} ) |
Sample Result |
{ 'a','ab','abc','abcd','abcde' } |
Version |
Requires Reporter x.y.z or higher. |
Signature |
List partialSum( List list, BinaryOp binOp ) |
Description |
Returns a list containing the partial sums of the elements in list. In other words, the ith element in the result is the sum of the 0th through ith elements in list. Addition is performed using the specified binOp expression; #this.l is the sum computed thus far, and #this.r is the next item in the list to be added. |
Sample Expression |
#f = :[ #this.l * #this.r ], #ENV.partialSum( {1,2,3,4,5}, #f ) |
Sample Result |
{ 1,2,6,24,120 } |
Version |
Requires Reporter x.y.z or higher. |
range
Signature |
List range( int start, int end ) |
Description |
Returns a list containing the integers start through end, inclusive. end is assumed to be greater than or equal to start. |
Sample Expression |
#ENV.range(5,10) |
Sample Result |
{ 5,6,7,8,9,10 } |
Version |
Requires Reporter x.y.z or higher. |
randomSample
Signature |
List randomSample( List list, int sampleSize ) |
Description |
Returns a list containing sampleSize elements randomly sampled from list. |
Sample Expression |
#ENV.randomSample( { 1,2,3,4,5,6 }, 3 ) |
Sample Result |
{ 1,3,4 } |
Version |
Requires Reporter x.y.z or higher. |
randomShuffle
Signature |
List randomShuffle( List list ) |
Description |
Returns a copy of list with the elements in randomly shuffled order. |
Sample Expression |
#ENV.reverse( { 1,2,3,4,5,6 } ) |
Sample Result |
{ 4,1,6,3,2,5 } |
Version |
Requires Reporter x.y.z or higher. |
reverse
Signature |
List reverse( List list ) |
Description |
Returns a copy of list with the elements in reverse order. |
Sample Expression |
#ENV.reverse( { 1,2,3,4,5,6 } ) |
Sample Result |
{ 6,5,4,3,2,1 } |
Version |
Requires Reporter x.y.z or higher. |
unique
Signature |
List unique( List list ) |
Description |
Returns a copy of list where consecutive equivalent elements have been removed. Elements are considered equivalent if they are equal according to the OGNL == (equality) operator, including any type conversions that may occur. |
Sample Expression |
#ENV.unique( { 1,1,2,2,2,3,2,4,5 } ) |
Sample Result |
{ 1,2,3,2,4,5 } |
Version |
Requires Reporter x.y.z or higher. |
Signature |
List unique( List list, BinaryPredicate predicate ) |
Description |
Returns a copy of list where consecutive equivalent elements have been removed. Elements are considered equivalent if predicate returns true. |
Sample Expression |
#f = :[ @@floor(#this.l / 2) == @@floor(#this.r / 2) ], #ENV.unique( { 0,1,2,3,4,5 }, #f ) |
Sample Result |
{ 0,2,4 } |
Version |
Requires Reporter x.y.z or higher. |