chunk
This built-in exists since FreeMarker 2.3.3.
This built-in splits a sequence into multiple sequences of the
          size given with the 1st parameter to the built-in (like
          mySeq?chunk(3)). The result is the sequence of
          these sequences. The last sequence is possibly shorter than the
          given size, unless the 2nd parameter is given (like
          mySeq?chunk(3, '-')), that is the item used to
          make up the size of the last sequence to the given size.
          Example:
<#assign seq = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j']>
<#list seq?chunk(4) as row>
  <#list row as cell>${cell} </#list>
</#list>
<#list seq?chunk(4, '-') as row>
  <#list row as cell>${cell} </#list>
</#list>    The output will be:
a b c d e f g h i j a b c d e f g h i j - -
This built in is mostly for outputting sequnces in
          tabular/columnar format. When used with HTML tables, the 2nd
          parameter is often "\xA0" (that is the code of
          the no-break space character, also known as "nbsp"), so
          the border of the empty TD-s will not be missing.
The 1st parameter must be a number that is at least 1. If the number is not integer, it will be silently rounded down to integer (i.e. both 3.1 and 3.9 will be rounded to 3). The 2nd parameter can be of any type and value.
drop_while
Returns a new sequence that contains the elements from the
          input sequence starting with from the first element that does
          not match the parameter predicate (condition).
          After that, all elements are included, regardless if they match the
          predicate or not. See the filter
          built-in for more details about parameters, and other
          details, but note that the condition in filter
          has opposite meaning (what to keep, instead of what to drop).
Example and comparison with filter:
<#assign xs = [1, 2, -3, 4, -5, 6]>
Drop while positive:
<#list xs?drop_while(x -> x > 0) as x>${x} </#list>
Filer for positives:
<#list xs?filter(x -> x > 0) as x>${x} </#list>    Drop while positive: -3 4 -5 6 Filer for positives: 1 2 4 6
As you can see, drop_while has stopped
          dropping the elements once it ran into the first element that didn't
          match the predicate (x > 0). On the other
          hand, filter keeps the elements that match the
          same predicate, and it doesn't stop.
See also: take_while
          built-in
filter
This built-in is available since 2.3.29
Returns a new sequence that only contains the elements for
          which the parameter condition (the predicate) returns
          true. For example:
<#assign xs = [1, -2, 3, 4, -5]>
Positives:
<#list xs?filter(x -> x > 0) as x>${x} </#list>
Negatives:
<#list xs?filter(x -> x < 0) as x>${x} </#list>    Positives: 1 3 4 Negatives: -2 -5
This built-in has a single required parameter, the predicate (filter condition, what to keep). The predicate can be specified in 3 ways:
- 
              
As a single argument lambda expression:
element -> predicate. In that,elementis the variable name with which you can refer to the current element in thepredicate, and thepredicateis an arbitrarily complex expression that must return a boolean value (trueorfalse). An example this was shown above. Note again the predicates can be arbitrarily complex, like the predicate inproducts?filter(product -> product.discounted && !user.hasBought(product)). - 
              
As a function or method that has a single argument, and returns boolean. For example, the "Negatives" example above could be implemented like this:
Template<#function negative(x)> <#return x < 0> </#function> ... Negatives: <#list xs?filter(negative) as x>${x} </#list>Note how we just referred to the function by name, and did not call it. Similarly, if you have a Java object called
utilsin the data-model, and it has aboolean isNegative(Number n)method, then you could use that likexs?filter(utils.isNegative). 
Remember, the condition (predicate) that you specify tells
            what to keep, not what to filter out! That
            is, the element will be in the result sequence when you return
            true, not when you return
            false. (It's like the WHERE
            condition in SQL, if you know that.)
While filter is most often used in the
          list
          directive, naturally it can be used anywhere where a filtered
          sequence is needed, and so this works as well:
<#assign negatives = xs?filter(x -> x < 0)>
Negatives:
<#list negatives as x>${x} </#list>    Note however, that for a very long sequences, the above
          solution can consume significantly more memory. That's because
          <list
          seq?filter(pred)
          ...> is optimized to do
          filtering without building an intermediate filtered sequence, while
          the n above example, assign will first build the
          whole filtered sequence in memory, and we pass that filtered
          sequence later to list. But again, this only
          matters for very long sequences.
See also: take_while
          built-in, drop_while
          built-in
Lazy evaluation and its consequences
Identical rules apply to these built-ins as well: map(mapper),
              take_while(predicate),
              drop_while(predicate).
To optimize processing, filter might
            delays fetching the elements of the input sequence, and applying
            the predicate on them. But it's guaranteed that those operations
            are not delayed past the point where the execution of the
            directive or interpolation, whose parameter contains the
            seq?filter(predicate),
            is finished. Some examples:
- 
                
In the case of
<list seq?filter(predicate) ...>nested content</#list>, when the execution enters thenested content, it's not true that all elements ofseqwas already consumed and filtered. Consuming and filteringseqis instead done bit by bit aslistrepeats the nested content. But it's guaranteed that past the</#list>tag (the end of the execution of thelistdirective), there are no delayed readings ofseq, or delayed evaluation of thepredicate. So avoid changing a such variable (or other system state) in the nested content oflist, which influences the result of thepredicate. Doing so could change the filtering for the rest of theseq. - 
                
In the case of
<#assign filteredSeq = seq?filter(predicate)>it's guaranteed that all elements ofseqwere processed, and thuspredicatewon't be evaluated after theassigndirective. - 
                
In the case of
${seq?filter(predicate)?join(', ')}it's guaranteed that all elements ofseqwere processed, and thuspredicatewon't be evaluated after theassigndirective. 
Inside expressions
            however, there's no promise regarding when the elements are
            consumed and when the predicate is evaluated. Like in the case of
            seq?filter(predicate1)?filter(predicate2),
            it's not guaranteed that
            predicate1 will only
            be evaluated before
            predicate2. (Most
            likely they will be called alternately:
            predicate1 for the
            1st element, then
            predicate2 for the
            1st element, then
            predicate1 for the
            2nd element, then
            predicate2 for the
            2nd element, and so on.)
If you pass a filtered sequence to a
            custom directive (a macro) or function or
            method, as in <@myMacro
            seq?filter(predicate)
            /> or
            myFunction(seq?filter(predicate)),
            then it's guaranteed that the filtering is not delayed past the
            point when the custom directive/function/method is invoked. That
            is, your macro/function/method will aways receive a fully
            constructed filtered sequence.
Also note that in it's not guaranteed that all elements of the input sequence will be read, and therefore that the predicate will be evaluated for all elements. Some examples of such cases:
- 
                
You may
breakout from<list seq?filter(predicate) ...>before it reaches the last element, in which case the rest of theseqelements won't be fetched and filtered. - 
                
In the case of
seq?filter(predicate)[2], which reads the 3rd element of the filtered sequence, FreeMarker stops fetching and filtering the elements ofseqwhen we have found the 3rd element that matches thepredicate. - 
                
In the case of
seq?filter(predicate)?size != 0, which tells whether the filtered sequence is non-empty, we stop fetching and filtering the elements ofseqwhen we have found the 1st element that matches thepredicate. (That's certainly surprising as?sizeneeds to process the whole sequence to tell the size. But in this case FreeMarker notices that we don't really need the exact size.) 
If you are a Java programmer, note how the
            filter built-in differs from Java
            Stream.filter. Stream.filter
            is "lazy", while FreeMarker filter
            is basically "eager", and is only "lazy"
            in special cases, and within a limited scope. Thus, unlike in
            Java, calling filter is not always free. In
            particular, if you assign a filtered sequence to a variable, or
            pass it to a custom directive/function/method, the filtered
            sequence will be created eagerly.
Filtering very long input that you don't hold in memory
Identical rules apply to these built-ins as well: map(mapper),
              take_while(predicate),
              drop_while(predicate).
Some applications, particularly those that render huge
            tables, use sequence-like
            values in the data-model that are not held in memory at
            once, instead they are like a stream of elements that you can only
            read in the order as they are given to you (on the Java side these
            are java.util.Iterator-s, or
            java.util.Iterables, or the like). These will
            have "collection" type in the template language,
            which is like a restricted sequence.
filter works with collection input too.
            As you have seen earlier, filter might stores
            the entire filtered sequence in the memory, which in this case
            sounds concerning, because if the input was too big to fit into
            the memory (hence it wasn't exposed as a sequence), then the
            filtered collection can be too big as well. For that reason, if
            the input is not a sequence (but a collection),
            filter never collects its result into the
            memory, and never fetches and processes the input elements until
            they are really needed ("lazy" behavior). Furthermore
            the result of filter is then a collection, not
            a sequence, therefor sequence operations (like
            seq[index])
            will not work on it.
Unlike with sequence input, any operation that would cause
            collecting the whole filtered result into the memory will now
            fail. Let's see that through examples. Let's say we have
            hugeTable in the data-model, which is not a
            sequence, but still a collection (probably an
            Iterator in Java). Then, consider:
<#-- Works: --> <#list hugeTable?filter(predicate) as row>nested content</#list>
This works fine, since list doesn't
            require collecting the result into the memory
Consider this:
<#-- Fails if hugeTable is not a sequence, just a collection: --> <#assign filteredHugeTable = hugeTable?filter(predicate)>
This fails, as filtering can't be postponed beyond the
            containing directive (assign), so FreeMareker
            had to put the entire filtered result into
            filteredHugeTable. If, however, you know that
            filteredHugeTable won't be too big, you can
            explicitly collect the result into a sequence via the sequence
            built-in:
<#-- Works, but be sure filtredHugeTable fits into the memory: --> <#assign filteredHugeTable = hugeTable?filter(predicate)?sequence>
Naturally, applying the sequence built-in
            allows all sequence operations, such as
            seq[index],
            seq[range],
            or
            seq?size.
            If these operations are directly applied on a sequence that was
            converted from a collection, then FreeMarker optimizes out
            actually creating the sequence in memory. So these won't consume
            much memory regardless of the size of the filtered
            hugeTable:
- 
                
hugeTable?filter(predicate)?sequence[index]: FreeMarker will just fetch and drop the elements till it reaches the element at the desired position. - 
                
hugeTable?filter(predicate)?sequence[0..9]: FreeMarker will just collect the first 10 elements. - 
                
hugeTable?filter(predicate)?sequence?size: In this case the wholehugeTablewill be fetched, which is possibly slow, but the fetched elements are still not collected into the memory, as they only need to be counted. 
Filtering missing (null) values
The argument to a lambda expression can hold the missing
            (Java null) value, and reading such value will
            not fall back to a higher scope. Thus, something like
            seq?filter(it -> it??), which filters out
            missing element from the sequence, will work reliably.
first
Returns the first item of the sequence. Thus
          value?first is the
          same as value[0],
          except that, since FreeMarker 2.3.26,
          value?first also works
          if value doesn't
          support getting items with numerical index, but still supports to be
          listed (i.e., with FTL collection values).
If the sequence or collection is empty, the result will be a
          missing value (as in
          empty?first!'No item was
          found').
join
Concatenates the items of a sequence to a single string, with the given separator. For example:
<#assign colors = ["red", "green", "blue"]>
${colors?join(", ")}    will output:
red, green, blue
Sequence items that are not strings will be converted to
          string with the same conversion rules as of
          ${...} (except, of
          course, no automatic escaping is applied at this stage).
?join(...) can
          have up to 3 parameters:
- 
              
Separator, required: The string that is inserted between items
 - 
              
Empty value, defaults to
""(empty string): The value used if the sequence contains no items. - 
              
List ending, defaults to
""(empty string): The value printed after the last value, if the list sequence wasn't empty. 
So this (where [] means an empty
          sequence):
${colors?join(", ", "-")}
${[]?join(", ", "-")}
${colors?join(", ", "-", ".")}
${[]?join(", ", "-", ".")}    will output:
red, green, blue - red, green, blue. -
Sequences coming from Java might contain
          null values. Those values will be ignored by this
          built-in, exactly like if they were removed from the list.
last
The last subvariable of the sequence. Template processing will die with error if the sequence is empty.
map
Returns an new sequence where all elements are replaced with
          the result of the parameter lambda, function, or method. For
          example, you have a list of user objects in
          users, but instead you need a list of user names
          in variable, then you could do this:
<#assign userNames = users?map(user -> user.name)>
The parameter work like the parameter of the with filter
          built-in (so see there), except that the
          lambda/function/method you specify can return values of any
          type.
Regarding lazy evaluation, and handling of very long inputs,
          it also works on the same
          way as the filter
          built-in.
min, max
Returns the smaller (min) or greatest
          (max) item of the sequence (or collection). The
          items must be either all numbers, or all date/time values of the
          same kind (date-only, time-only, date-time), or else a comparison
          error will occur. These are the same restrictions as for the < and
          > operators.
Missing items (i.e., Java null-s) will be
          silently ignored. If the sequence is empty or it only contains
          missing (Java null) items, the result itself will
          be missing.
Example:
${[1, 2, 3]?min}
${[1, 2, 3]?max}
${[]?min!'-'}    1 3 -
reverse
The sequence with reversed order.
seq_contains
The seq_ prefix is required in the
            built-in name to differentiate it from the contains
            built-in that searches a substring in a string (since a
            variable can be both string and sequence on the same time).
Tells if the sequence contains the specified value (according
          the ==
          operator of the template language, not according Java's
          Object.equals). It has 1 parameter, the value to
          find. Example:
<#assign x = ["red", 16, "blue", "cyan"]>
"blue": ${x?seq_contains("blue")?string("yes", "no")}
"yellow": ${x?seq_contains("yellow")?string("yes", "no")}
16: ${x?seq_contains(16)?string("yes", "no")}
"16": ${x?seq_contains("16")?string("yes", "no")}    The output will be:
"blue": yes "yellow": no 16: yes "16": no
To find the value the built-in uses FreeMarker's comparison
          rules (as if you was using ==
          operator), except that comparing two values of different
          types or of types for which FreeMarker doesn't support comparison
          will not cause error, just will be evaluated as the two values are
          not equal. Thus, you can use it only to find scalar values (i.e.
          string, number, boolean or date/time values). For other types the
          result will be always false.
For fault tolerance, this built-in also works with collections.
seq_index_of
This built-in is available since FreeMarker 2.3.1. It doesn't exist in 2.3.
The seq_ prefix is required in the
            built-in name to differentiate it from the index_of
            built-in that searches a substring in a string (since a
            variable can be both string and sequence on the same time).
Returns the index of the first occurrence of a value in the
          sequence, or -1 if the sequence doesn't contain
          the specified value. The value to find is specified as the first
          parameter. For example this template:
<#assign colors = ["red", "green", "blue"]>
${colors?seq_index_of("blue")}
${colors?seq_index_of("red")}
${colors?seq_index_of("purple")}    will output this:
2 0 -1
To find the value the built-in uses FreeMarker's comparison
          rules (as if you was using ==
          operator), except that comparing two values of different
          types or of types for which FreeMarker doesn't support comparison
          will not cause error, just will be evaluated as the two values are
          not equal. Thus, you can use it only to find scalar values (i.e.
          string, number, boolean or date/time values). For other types the
          result will be always -1.
The index where the searching is started can be optionally given as the 2nd parameter. This may be useful if the same item can occur for multiple times in the same sequence. There is no restriction on the numerical value of the second parameter: if it is negative, it has the same effect as if it were zero, and if it is greater than the length of the sequence, it has the same effect as if it were equal to the length of the sequence. Decimal values will be truncated to integers. For example:
<#assign names = ["Joe", "Fred", "Joe", "Susan"]>
No 2nd param: ${names?seq_index_of("Joe")}
-2: ${names?seq_index_of("Joe", -2)}
-1: ${names?seq_index_of("Joe", -1)}
 0: ${names?seq_index_of("Joe", 0)}
 1: ${names?seq_index_of("Joe", 1)}
 2: ${names?seq_index_of("Joe", 2)}
 3: ${names?seq_index_of("Joe", 3)}
 4: ${names?seq_index_of("Joe", 4)}    will output this:
No 2nd param: 0 -2: 0 -1: 0 0: 0 1: 2 2: 2 3: -1 4: -1
seq_last_index_of
This built-in is available since FreeMarker 2.3.1. It doesn't exist in 2.3.
The seq_ prefix is required in the
            built-in name to differentiate it from the last_index_of
            built-in that searches a substring in a string (since a
            variable can be both string and sequence on the same time).
Returns the index of the last occurrence of a value in the
          sequence, or -1 if the sequence doesn't contain
          the specified value. That is, it is the same as seq_index_of,
          just it searches backward starting from the last item of the
          sequence. It also supports the optional 2nd parameter that specifies
          the index where the searching is started. For example:
<#assign names = ["Joe", "Fred", "Joe", "Susan"]>
No 2nd param: ${names?seq_last_index_of("Joe")}
-2: ${names?seq_last_index_of("Joe", -2)}
-1: ${names?seq_last_index_of("Joe", -1)}
 0: ${names?seq_last_index_of("Joe", 0)}
 1: ${names?seq_last_index_of("Joe", 1)}
 2: ${names?seq_last_index_of("Joe", 2)}
 3: ${names?seq_last_index_of("Joe", 3)}
 4: ${names?seq_last_index_of("Joe", 4)}    will output this:
No 2nd param: 2 -2: -1 -1: -1 0: 0 1: 0 2: 2 3: 2 4: 2
size
The number of sub variables in sequence (as a numerical
          value). The highest possible index in sequence s
          is s?size - 1 (since the index of the first
          subvariable is 0) assuming that the sequence has at least one
          subvariable.
sort
Returns the sequence sorted in ascending order. (For
          descending order use this and then the reverse built
          in.) This will work only if all sub variables are strings, or
          if all sub variables are numbers, or if all sub variables are date
          values (date, time, or date+time), or if all sub variables are
          booleans (since 2.3.17). If the sub variables are strings, it uses
          locale (language) specific lexical sorting (which is usually not
          case sensitive). For example:
<#assign ls = ["whale", "Barbara", "zeppelin", "aardvark", "beetroot"]?sort>
<#list ls as i>${i} </#list>    will print (with US locale at least):
aardvark Barbara beetroot whale zeppelin
sort_by
Returns the sequence of hashes sorted by the given hash
          subvariable in ascending order. (For descending order use this and
          then the reverse built
          in.) The rules are the same as with the sort built-in,
          except that the sub variables of the sequence must be hashes, and
          you have to give the name of a hash subvariable that will decide the
          order. For example:
<#assign ls = [
  {"name":"whale", "weight":2000},
  {"name":"Barbara", "weight":53},
  {"name":"zeppelin", "weight":-200},
  {"name":"aardvark", "weight":30},
  {"name":"beetroot", "weight":0.3}
]>
Order by name:
<#list ls?sort_by("name") as i>
- ${i.name}: ${i.weight}
</#list>
Order by weight:
<#list ls?sort_by("weight") as i>
- ${i.name}: ${i.weight}
</#list>    will print (with US locale at least):
Order by name: - aardvark: 30 - Barbara: 53 - beetroot: 0.3 - whale: 2000 - zeppelin: -200 Order by weight: - zeppelin: -200 - beetroot: 0.3 - aardvark: 30 - Barbara: 53 - whale: 2000
If the subvariable that you want to use for the sorting is on a deeper level (that is, if it is a subvariable of a subvariable and so on), then you can use a sequence as parameter, that specifies the names of the sub variables that lead down to the desired subvariable. For example:
<#assign members = [
    {"name": {"first": "Joe", "last": "Smith"}, "age": 40},
    {"name": {"first": "Fred", "last": "Crooger"}, "age": 35},
    {"name": {"first": "Amanda", "last": "Fox"}, "age": 25}]>
Sorted by name.last:
<#list members?sort_by(['name', 'last']) as m>
- ${m.name.last}, ${m.name.first}: ${m.age} years old
</#list>    will print (with US locale at least):
Sorted by name.last: - Crooger, Fred: 35 years old - Fox, Amanda: 25 years old - Smith, Joe: 40 years old
take_while
Returns a sequence that only contains the elements of the
          input sequence which are before the first element that doesn't match
          the parameter predicate (filter condition). This is very similar to
          the filter
          built-in, so see further details there.
Example and comparison with filter:
<#assign xs = [1, 2, -3, 4, -5, 6]>
Take while positive:
<#list xs?take_while(x -> x > 0) as x>${x} </#list>
Filer for positives:
<#list xs?filter(x -> x > 0) as x>${x} </#list>    Take while positive: 1 2 Filer for positives: 1 2 4 6
As you can see, take_while has stopped at
          the first number that didn't match the predicate (x >
          0), while filter has continued finding
          further matches.
See also: drop_while
          built-in
