What You’ll Learn in This Module
In Module 2, you learned what arrays are and how to create them with split. In this module, you’ll master the complete set of array filters — the tools for joining arrays back into text, accessing specific items, sorting, removing duplicates, reversing order, and counting. These filters turn raw multi-value CRM data into polished, dynamic narration content.
When Do You Work with Arrays in Cast?
Arrays appear in Cast narrations whenever you deal with lists of things:
- Features a customer uses (
"Analytics,Reporting,Alerts") - Open support tickets or action items
- Products in a customer’s subscription
- Regions or countries in a territory
- Team members or stakeholders
These typically arrive from your CRM as comma-separated strings. The workflow is almost always the same:
- Split the string into an array
- Transform the array (sort, deduplicate, limit)
- Output the array (loop through it, join it, or count it)
Excel analogy: Working with arrays in Liquid is like working with a filtered column in a spreadsheet. You can sort it (A–Z or Z–A), remove duplicates, count the rows, grab the first or last entry, or join all the values into a single cell separated by commas.
Quick Reference — All Array Filters
| Filter | What It Does | Input → Output |
|---|---|---|
join: ", " | Join array items into a single string | ["a","b","c"] → "a, b, c" |
first | Get the first item | ["a","b","c"] → "a" |
last | Get the last item | ["a","b","c"] → "c" |
size | Count items | ["a","b","c"] → 3 |
sort | Sort alphabetically (A→Z) | ["c","a","b"] → ["a","b","c"] |
uniq | Remove duplicate items | ["a","a","b"] → ["a","b"] |
reverse | Reverse the order | ["a","b","c"] → ["c","b","a"] |
join — Combine Array Items into a String
What is it?
The join filter takes an array and combines all its items into a single string, with a separator of your choice between each item. It’s the opposite of split.
Excel analogy: Like
=TEXTJOIN(", ", TRUE, A1:A5)— combining a column of cells into one cell with commas between them.
Why it matters in Cast
When you need to display a list of items in a sentence (rather than as a bullet list), join creates a natural, readable string.
Liquid syntax
{% assign items = "Analytics,Reporting,Alerts" | split: "," %}
{{ items | join: ", " }} → "Analytics, Reporting, Alerts"
{{ items | join: " | " }} → "Analytics | Reporting | Alerts"
{{ items | join: " and " }} → "Analytics and Reporting and Alerts"
Real Cast example
{%- assign features = feature_list | split: "," -%}
{%- assign clean_features = "" | split: "" -%}
{% comment %} Strip each item for clean output {% endcomment %}
{%- for f in features -%}
{%- assign stripped = f | strip -%}
{%- assign clean_features = clean_features | append: stripped | append: "," | split: "," -%}
{%- endfor -%}
Your active features include {{ clean_features | join: ", " }}.
💡 For simple cases where the items don’t have extra spaces, you can skip the stripping loop:
{%- assign features = feature_list | split: "," -%}
Your active features include {{ features | join: ", " }}.
If feature_list is "Analytics,Reporting,Alerts": Output: Your active features include Analytics, Reporting, Alerts.
Common mistakes
❌ Using join on a string instead of an array:
{{ feature_list | join: ", " }}
If feature_list is still a comma-separated string (not split into an array), join has nothing to join — it just passes the string through unchanged.
✅ Split first, then join:
{{ feature_list | split: "," | join: ", " }}
first and last — Access the Ends of an Array
What is it?
The first filter returns the first item in an array. The last filter returns the last item. Neither changes the array itself.
Excel analogy:
firstis like referencing the top cell in a column (=A1).lastis like using=INDEX(A:A, COUNTA(A:A))to get the last filled cell.
Why it matters in Cast
Use first and last to highlight a specific item — the top feature, the most recent ticket, or the primary product — without needing a loop.
Liquid syntax
{% assign items = "Analytics,Reporting,Alerts" | split: "," %}
{{ items | first }} → "Analytics"
{{ items | last }} → "Alerts"
Real Cast example
{%- assign tasks = open_tasks | split: "," -%}
Your highest-priority open item is: {{ tasks | first | strip }}.
If open_tasks is "Renew contract,Schedule QBR,Update health score": Output: Your highest-priority open item is: Renew contract.
You can also access items by numeric position (index), starting at 0:
{{ tasks[0] | strip }} → "Renew contract" (same as first)
{{ tasks[1] | strip }} → "Schedule QBR"
{{ tasks[2] | strip }} → "Update health score" (same as last, for 3-item array)
Common mistakes
❌ Assuming first returns position 1: Array positions start at 0. first returns position 0, which is the first item.
❌ Using first on an empty array without a guard:
{{ empty_list | split: "," | first }}
If the source string is empty, the array is empty, and first returns nil — which may error in strict mode.
✅ Check the array size first:
{%- assign items = some_list | split: "," -%}
{% if items.size > 0 %}
Top item: {{ items | first | strip }}
{% else %}
No items on file.
{% endif %}
size — Count Array Items
What is it?
When applied to an array, size returns the number of items in it. (You already saw size on strings in Module 4, where it counts characters. The same filter works on both types.)
Excel analogy: Like
=COUNTA(A1:A10)— counting the non-empty cells in a range.
Why it matters in Cast
Counting items lets you show dynamic totals (“You have 5 open tasks”) and make decisions based on quantity (“if they have more than 3 features…”).
Liquid syntax
{% assign items = "a,b,c,d,e" | split: "," %}
{{ items | size }} → 5
You can also use .size (dot notation) in conditions:
{% if items.size > 3 %}
You're a power user with {{ items.size }} active features.
{% endif %}
Real Cast example
{%- assign features = feature_list | split: "," -%}
{% if features.size == 0 %}
No features are currently active on your account.
{% elsif features.size <= 3 %}
You're using {{ features.size }} features. There's room to explore more!
{% else %}
You're actively using {{ features.size }} features — great engagement.
{% endif %}
sort — Alphabetical Sorting
What is it?
The sort filter arranges array items in alphabetical (A–Z) order. Numbers are sorted as strings (so "10" comes before "9" alphabetically).
Excel analogy: Like clicking “Sort A to Z” on a column.
Why it matters in Cast
Use sort when the order items arrive from the CRM is inconsistent and you want a predictable, clean presentation.
Liquid syntax
{% assign items = "Reporting,Analytics,Alerts" | split: "," %}
{{ items | sort | join: ", " }} → "Alerts, Analytics, Reporting"
Real Cast example
{%- assign features = feature_list | split: "," -%}
{%- assign sorted_features = features | sort -%}
Your features (alphabetical):
{% for feature in sorted_features %}
{{ forloop.index }}. {{ feature | strip }}
{% endfor %}
Common mistakes
❌ Expecting numeric sort on number strings:
{% assign numbers = "10,2,30,1" | split: "," %}
{{ numbers | sort | join: ", " }} → "1, 10, 2, 30" (alphabetical, not numeric!)
Alphabetically, "10" comes before "2" because "1" < "2".
✅ There’s no built-in numeric sort in Liquid. If you need to sort numbers, you’ll generally want to ensure consistent formatting (zero-padding) or handle the sorting in your data source before it reaches Cast.
uniq — Remove Duplicates
What is it?
The uniq filter removes duplicate items from an array, keeping only the first occurrence of each unique value.
Excel analogy: Like the “Remove Duplicates” button on the Data tab.
Why it matters in Cast
CRM data sometimes contains duplicates — a feature might be listed twice, or a region might appear multiple times. uniq ensures your lists are clean.
Liquid syntax
{% assign items = "Analytics,Reporting,Analytics,Alerts,Reporting" | split: "," %}
{{ items | uniq | join: ", " }} → "Analytics, Reporting, Alerts"
{{ items | uniq | size }} → 3
Real Cast example
{%- assign raw_regions = region_list | split: "," -%}
{%- assign regions = raw_regions | uniq -%}
You have active users in {{ regions | size }} unique regions:
{{ regions | join: ", " }}.
If region_list is "EMEA,APAC,EMEA,NAM,APAC": Output: You have active users in 3 unique regions: EMEA, APAC, NAM.
Common mistakes
❌ Expecting uniq to be case-insensitive:
{% assign items = "Analytics,analytics,ANALYTICS" | split: "," %}
{{ items | uniq | join: ", " }} → "Analytics, analytics, ANALYTICS"
All three are considered different because uniq is case-sensitive.
✅ Normalize case before deduplicating:
{%- assign raw = "Analytics,analytics,ANALYTICS" | downcase | split: "," -%}
{{ raw | uniq | join: ", " }} → "analytics"
reverse — Flip the Order
What is it?
The reverse filter reverses the order of items in an array. The last item becomes the first, the first becomes the last.
Excel analogy: Like sorting a column Z–A (if it was originally A–Z), or simply flipping the column upside down.
Why it matters in Cast
Use reverse when your data arrives in one order but you want to present it in the opposite order — for example, showing the most recent items first when they arrive oldest-first.
Liquid syntax
{% assign items = "a,b,c,d,e" | split: "," %}
{{ items | reverse | join: ", " }} → "e, d, c, b, a"
Descending sort — combine sort and reverse:
{% assign items = "Reporting,Analytics,Alerts" | split: "," %}
{{ items | sort | reverse | join: ", " }} → "Reporting, Analytics, Alerts"
Real Cast example
{%- assign milestones = milestone_list | split: "," -%}
{%- assign recent_first = milestones | reverse -%}
Your most recent milestones:
{% for milestone in recent_first limit: 3 %}
{{ forloop.index }}. {{ milestone | strip }}
{% endfor %}
If milestones arrive chronologically ("Onboarding, Go-Live, First QBR, Expansion") and you want the most recent shown first:
Your most recent milestones:
1. Expansion
2. First QBR
3. Go-Live
Chaining Array Filters
Just like text filters, array filters can be chained to build a multi-step pipeline:
{%- assign raw_features = feature_list | split: "," -%}
{%- assign clean = raw_features | uniq | sort -%}
You have {{ clean | size }} unique features:
{{ clean | join: ", " }}.
Common chain patterns:
| Goal | Chain |
|---|---|
| Split, deduplicate, count | split: "," \| uniq \| size |
| Split, sort A–Z, join | split: "," \| sort \| join: ", " |
| Split, sort Z–A, take first 3 | split: "," \| sort \| reverse + limit: 3 in loop |
| Split, deduplicate, sort | split: "," \| uniq \| sort |
Combining Array Filters with Loops
Array filters prepare your data; for loops (Module 14) display it. Here’s the complete pattern:
{%- assign features = feature_list | split: "," -%}
{%- assign sorted = features | uniq | sort -%}
{% if sorted.size == 0 %}
No active features on your account.
{% elsif sorted.size <= 3 %}
Your active features: {{ sorted | join: ", " }}.
{% else %}
Your {{ sorted | size }} active features:
{% for feature in sorted limit: 5 %}
{{ forloop.index }}. {{ feature | strip }}
{% endfor %}
{% if sorted.size > 5 %}
...and {{ sorted.size | minus: 5 }} more.
{% endif %}
{% endif %}
This handles three cases: no features, a short list (displayed inline with join), and a long list (displayed as numbered items with a “and X more” overflow).
Try It Yourself — Module 6 Capstone Exercise
Exercise: You have a variable product_list with the value "Pro,Enterprise,Starter,Pro,Enterprise,Pro". Write Liquid that:
- Splits it into an array
- Removes duplicates
- Sorts alphabetically
- Displays the count of unique products
- Joins them into a sentence like “Your products: Enterprise, Pro, Starter.”
Click to reveal the answer
```liquid {%- assign products = product_list | split: "," -%} {%- assign unique_products = products | uniq | sort -%} You have {{ unique_products | size }} unique products. Your products: {{ unique_products | join: ", " }}. ``` Output: ``` You have 3 unique products. Your products: Enterprise, Pro, Starter. ``` Step by step: - `split: ","` → `["Pro","Enterprise","Starter","Pro","Enterprise","Pro"]` - `uniq` → `["Pro","Enterprise","Starter"]` - `sort` → `["Enterprise","Pro","Starter"]` - `size` → 3 - `join: ", "` → `"Enterprise, Pro, Starter"`What’s Next
In Module 7, you’ll learn about dates and date formatting — how to display dates in any format, work with the current date, and perform date arithmetic for use cases like days-until-renewal or customer tenure calculations.
📖 Official documentation:
- Standard Filters: https://school.cast.app/liquid/liquid-filters.html
- Tags/Blocks (for loops): https://school.cast.app/liquid/liquid-blocks.html