Start page / Template development / Template syntax / Expressions / Mapping expressions

Mapping expressions (lambda)Available from FirstSpirit Version 4.1

A mapping expression (also called a "lambda expression") is an anonymous function, which contains expressions and instructions. It is represented in FirstSpirit by the -> operator ("lambda", an arrow consisting of a minus sign immediately followed by a greater than sign). This roughly means "switches to" or "maps ... on".

A freely selectable input parameter is given on the left-hand side of the lambda operator. This is a so-called "anonymous" input parameter, which is quasi a wildcard for an object (e.g. a set of values, in FirstSpirit: Lists). The value can only be accessed within the interpretation, and is therefore only of interest during the execution.

There is an expression or instruction block on the right-hand side.

Example:

The lambda expression

x -> x * x

means

"x is multiplied by itself x times"

Depending on the use case, different methods can be used on the right-hand side:

1st example: Sorting using the "sort(Lambda)" method

If lists or maps have several attributes per element (comparable with a dataset with several columns), the elements can be sorted by the individual attributes using lambda (->).

In the following example, $CMS_SET(...)$ is used to generate a list of key value pairs ("Map"). Each map contains a name ("name") and a login ("login") for each element:

$CMS_SET(_members, [
{
"name": "Max Mustermann",
"login" : "mustermann"
}, {
"name" : "Tina Testuser",
"login" : "testuser"
}, {
"name" : "Maxine Musterfrau",
"login" : "musterfrau"
}
])$

The elements in this list can now be output with the help of a $CMS_FOR(...)$ loop and the sort method sorted in ascending order by the "login" key:

$CMS_FOR(_member, _members.sort(x -> x["login"]))$
$CMS_VALUE(_member["name"] + " (" + _member["login"] + ")")$<br />
$CMS_END_FOR$

First, the list (_members) is sorted in ascending alphabetical order with the help of the sort function on the basis of the "login" key. To this end, the lambda expression does not take into account the element itself (one map each) for the sorting, but instead it uses the value of the "login" key (from the map). The $CMS_FOR(...)$ loop is then used to iterate through the sorted list and the name and login is returned in round commas via the $CMS_VALUE(...)$ expression.

The output looks like the following:

Maxine Musterfrau (musterfrau)
Max Mustermann (mustermann)
Tina Testuser (testuser)

Below you will find another way for sorting lists by different criteria by means of the lambda expression:

This list of maps for example contains names consisting of christian name and last name:

$CMS_SET(_members, [
{
"name" : "Redakteur",
"cname" : "Rudi"
}, {
"name" : "Mustermann",
"cname" : "Sven"
}, {
"name": "Testuser",
"cname" : "Anne"
}, {
"name" : "Mustermann",
"cname" : "Stefan"
}
])$

Using the following instruction the names can be output sorted by last name and then by christian name in ascending alphabetical order. Last and christian name are separated by a comma.

$CMS_FOR(_member, _members.sort(x -> x.cname).sort(x -> x.name))$
$CMS_VALUE(#for.index + 1)$. $CMS_VALUE(_member.name)$, $CMS_VALUE(_member.cname)$
$CMS_END_FOR$

The names are output in this order:

  1. Mustermann, Stefan
  2. Mustermann, Sven
  3. Redakteur, Rudi
  4. Testuser, Anne

2nd example: Filtering using the "max(Lambda)" and "min(Lambda)" methods

In the following example a list of maps is also generated, namely on real estate properties ("immos") with various information such as address, price and size:

$CMS_SET(immos, [
{"Name":"A", "Address":{"Town":"Dortmund", "PostCode":42400, "Street":"Amsterdamer Platz", "HouseNo":"32"}, "Price":177000, "sqmSize":190},
{"Name":"B", "Address":{"Town":"Bochum", "PostCode":44877, "Street":"Allestr.", "HouseNo":"114"}, "Price":150000, "sqmSize":150},
{"Name":"C", "Address":{"Town":"Hagen", "PostCode":42345, "Street":"Kleiner Weg", "HouseNo":"2b"}, "Price":555000, "sqmSize":320},
{"Name":"D", "Address":{"Town":"Bochum", "PostCode":44890, "Street":"Zeppelindamm", "HouseNo":"93"}, "Price":352000, "sqmSize":210}
])$

The max and min methods can be used to output the most expensive or least expensive property:

Most expensive property:
$CMS_VALUE(immos.max(x -> x.Price))$<br>
Least expensive property:
$CMS_VALUE(immos.min(x -> x.Price))$<br>

Output:

Most expensive property: {Address={HouseNo=2b, Town=Hagen, PostCode=42345, Street=Kleiner Weg}, Name=C, Price=555000, sqmSize=320}
Least expensive property: {Address={HouseNo=114, Town=Bochum, PostCode=44877, Street=Allestr.}, Name=B, Price=150000, sqmSize=150}

3rd example: Filtering elements using the "filter(Lambda)" method

From the list defined above, the filter method can be used to output properties whose price exceeds a specific value (here: > 200000):

$CMS_FOR(_property, _properties.filter(x -> x.Price > 200000))$
$CMS_VALUE(_property.Price)$ ($CMS_VALUE(_property.Name)$)<br/>
$CMS_END_FOR$

In this way, the properties whose value exceeds 200000 are output with their price and name:

555000 (C)
352000 (D)

4th example: Output of list elements in a collection using the "map(Lambda)" method

From the list defined above, the sort method can be used to sort the prices of the properties in ascending order and the map method can be used to output them as a collection:

Sorted property prices:
$CMS_VALUE(immos.map(x -> x.Price)).sort())$<br>

Output:

Sorted property prices: [150000, 177000, 352000, 555000]

5th example: Filtering duplicates using the "filter(Lambda)" method

If duplicates are to be filtered out of a list of key value pairs when it is output, this can also be done using the filter method.

If the list defined above is extended to include properties with postal codes which already exist, e.g.

$CMS_SET(immos, [
{"Name":"A", "Address":{"Town":"Dortmund", "PostCode":42400, "Street":"Amsterdamer Platz", "HouseNo":"32"}, "Price":177000, "sqmSize":190},
{"Name":"A2", "Address":{"Town":"Dortmund", "PostCode":42400, "Street":"Amsterdamer Weg", "HouseNo":"3"}, "Price":153000, "sqmSize":100},
{"Name":"B", "Address":{"Town":"Bochum", "PostCode":44877, "Street":"Alleestr.", "HouseNo":"114"}, "Price":150000, "sqmSize":150},
{"Name":"B2", "Address":{"Town":"Bochum", "PostCode":42400, "Street":"Barcelonaweg", "HouseNo":"3"}, "Price":203000, "sqmSize":140},
{"Name":"C", "Address":{"Town":"Hagen", "PostCode":42345, "Street":"Kleiner Weg", "HouseNo":"2b"}, "Price":555000, "sqmSize":320},
{"Name":"C2", "Address":{"Town":"Hagen", "PostCode":42345, "Street":"Großer Weg", "HouseNo":"22"}, "Price":775000, "sqmSize":220},
{"Name":"D", "Address":{"Town":"Bochum", "PostCode":44890, "Street":"Zeppelindamm", "HouseNo":"93"}, "Price":352000, "sqmSize":210},
{"Name":"D2", "Address":{"Town":"Bochum", "PostCode":44890, "Street":"Zeppelinweg", "HouseNo":"39"}, "Price":552000, "sqmSize":110}
])$

, the instruction

$CMS_VALUE(immos.map(x -> x.Address.PostCode).filter(x -> x > 42000 && x < 43000).iterator.toSet)$

and/or

$CMS_SET(_value, {})$
$CMS_SET(_void, _value.addAll(immos.map(x -> x.Address.PostCode).filter(x -> x > 42000 && x < 43000)))$
$CMS_VALUE(_value)$

can be used to return all postal codes within the range from 42000 to 43000 without duplicates, for which a property was recorded.

Output:

[42345, 42400]

6th example: Output of a list of unique elements using the "distinct(Lambda)" method

The distinct method is used to eliminate or ignore duplicates of a list according to a given condition. This method can be used for glossaries or summaries, which can then serve linked, for example, as navigational element.

Example glossary / index

To create an index of initial letters from a list with first names, on the list

$CMS_SET(_names, ["Birgit", "Andreas", "Barbara", "Emma", "Anne", "Celine"])$

the following instruction can be executed:

$CMS_FOR(_name, _names.distinct(x -> x.charAt(0)).sort)$
$CMS_IF(!#for.isFirst)$ | $CMS_END_IF$
$CMS_VALUE(_name.charAt(0))$
$CMS_END_FOR$

In this example the first entry for a initial letter of the register is first be identified in a $CMS_FOR(...)$ instruction by means of the method distinct. The result is:

Birgit, Andreas, Emma, Celine

The identified elements are then sorted by means of sort (ascending in alphabetical order). Result:

Andreas, Birgit, Celine, Emma

Then the first letter of the identified elements is output by means of the $CMS_VALUE(...)$ instruction, separated by a vertical line | :

A | B | C | E
Important The entries "Barbara" and "Anne" are ignored in this example, because distinct always considers the first occurence of names beginning with the same letter. If the list of names would be sorted alphabetically first (sort) and then the method distinct would be applied, the entries "Birgit" and "Anne" would be deleted, because, in alphabetical order, they follow "Barbara" and "Andreas" .

Example summary

A summary of postal codes is created from a list with real estates in the following example, several properties have the same postal code. The intention is it consequently to eliminate duplcates of postal codes, all further information about the real estates are not relevant.

$CMS_SET(immos, [
{"Name":"A", "Adress":{"Town":"Dortmund", "ZIP":44400, "Street":"Amsterdamer Platz", "No":"32"}, "Price":177.000, "sqmSize":190},
{"Name":"B", "Adress":{"Town":"Dortmund", "ZIP":44400, "Street":"Amsterdamer Weg", "No":"64"}, "Price":180.000, "sqmSize":195},
{"Name":"C", "Adress":{"Town":"Dortmund", "ZIP":41877, "Street":"Alleestr.", "No":"114"}, "Price":150.000, "sqmSize":150},
{"Name":"D", "Adress":{"Town":"Dortmund", "ZIP":41877, "Street":"Buchenweg", "No":"11"}, "Price":115.000, "sqmSize":100},
{"Name":"E", "Adress":{"Town":"Bochum", "ZIP":42345, "Street":"Kleiner Weg", "No":"2b"}, "Price":555.000, "sqmSize":320},
{"Name":"F", "Adress":{"Town":"Bochum", "ZIP":42345, "Street":"Hohe Straße", "No":"6"}, "Price":55.000, "sqmSize":64},
{"Name":"G", "Adress":{"Town":"Bochum", "ZIP":42345, "Street":"Tiefer Weg", "No":"21"}, "Price":38.000, "sqmSize":37}
])$

Using a $CMS_FOR(...)$ instruction the list of real estates is first sorted by postal code by means of the method sort (ascending). Then the first entries for one postal code are identified with the method distinct and output via $CMS_VALUE(...)$:

<h4>Overview of our real estates by postal code:</h4>
$CMS_FOR(_immo, immos.sort(x -> x.Adress.ZIP).distinct(x -> x.Adress.ZIP))$
* $CMS_VALUE(_immoAdress.ZIP)$<br />
$CMS_END_FOR$

The output will be:

Overview of our real estates by postal code:
* 41877
* 42345
* 44400
Important The entries of the real estates "B", "D", "F" and "G" are ignored in this example, too, because of using the method distinct, since only the first entry for one postal code is considered.

7th example: Sum of a number series (Σ sum) with "fold(Lambda)"

Lambda can also be used to determine the sum of a number series, e.g. the sum of the numbers from 1 to 5:

1 + 2 + 3 + 4 + 5 = ?

This is done using the fold method, e.g.:

$CMS_VALUE([1..5].fold(s : 0, x -> s + x))$

The anonymous fold function has two parameters:

  • The first parameter defines the input parameter and its start value (in the example: "s : 0").
  • The second parameter is a lambda expression, in which s can be used (in the example "x -> s + x", whereby x is the input parameter of the lambda expression, s + x of the expression). The value of s is therefore continuously adjusted during the interpretation.

At the end, the value of s is output. x is always a value from the values set.

In the 1st pass the input parameter of the fold function s has the start value (s=0) and the input parameter of the lambda expression x has the value of the first element ("1"). The value of s in the expression is therefore increased by the value "1", so that the value of s is "1", in short form:

s=0,  x=1   =>   s = s + x   =   0 + 1   =   1

In the 2nd pass, the value of s is "1" (s=2). x has the value of the second element ("2"). The value of s is now "3":

s=1,  x=2   =>   s = s + x   =   1 + 2   =   3

In the 3rd pass the value of s is "3" (s=3). x has the value of the third element ("3"). The value of s is now "10":

s=3,  x=3   =>   s = s + x   =   3 + 3   =   6

In the 4th pass the value of s is "6" (s=6). x has the value of the fourth element ("4"). The value of s is now "6":

s=6,  x=4   =>   s = s + x   =   6 + 4   =   10

In the 5th pass the value of s is "10" (s=10). x has the value of the fifth element ("5"). The value of s is now "6":

s=10,  x=5   =>   s = s + x   =   10 + 5   =   15

The end result is therefore 15.

8th example: Product of a number series (Π product) with "fold(Lambda)"

The fold method is also used to calculate products from number series (see also 6th example), e.g.:

$CMS_VALUE([1..4].fold(p : 1, x -> p*x))$

In this example the product of the numbers 1 to 4 is determined, i.e.

1 * 2 * 3 * 4 = ?

p is the input parameter and the start value of the fold function. The product formation begins with this value.

In the 1st pass the input parameter of the fold function p has the start value (p=1) and the input parameter of the lambda expression x has the value of the first element ("1"). In the expression, the value of p is multiplied by the value "1", so that the value of p is "1", in short:

p=1,  x=1   =>   p = p * x   =   1 * 1   =   1

In the 2nd pass the value of p is "1" (p=1). x has the value of the second element ("2"). The value of p is now "2":

p=1,  x=2   =>   p = p * x   =   1 * 2   =   2

In the 3rd pass the value of p is "2" (p=2). x has the value of the third element ("3"). The value of p is now "6":

p=2,  x=3   =>   p = p * x   =   2 * 3   =   6

In the 4th pass the value of p is "6" (p=6). x has the value of the fourth element ("4"). The value of p is now "24":

p=6,  x=4   =>   p = p * x   =   6 * 4   =   24

The end result is therefore 24.

© 2005 - 2024 Crownpeak Technology GmbH | All rights reserved. | FirstSpirit 2024.4 | Data privacy