Lists and Delimiters
Lists and Delimiters
Lists are the fundamental data structure in MUSH softcode. There are no arrays, no hash maps, no structs—just strings, and strings that you treat as lists by splitting them on a delimiter character.
What Is a List?
A list is a string of values separated by a delimiter. By default, the delimiter is a space:
apple banana cherry
This is a list of three elements. The function words(apple banana cherry) returns 3.
Delimiters
Many list functions accept an optional delimiter argument:
[iter(red|green|blue, ## is a color, |)]
Here, | is the delimiter instead of space. Common delimiters include | (pipe), , (comma), and ~ (tilde). The choice of delimiter matters when your data might contain spaces.
Some servers support multi-character delimiters. In TinyMUX, delimiters are single characters.
Output Delimiters
Many functions that produce lists accept both an input delimiter and an output delimiter:
[sort(cherry|apple|banana, , |, |)]
This sorts a pipe-delimited list and produces pipe-delimited output.
Core List Functions
| Function | Purpose |
|---|---|
words(list) | Count elements |
first(list) | First element |
last(list) | Last element |
rest(list) | Everything except the first element |
extract(list, pos, len) | Extract elements by position |
insert(list, pos, value) | Insert at position |
ldelete(list, pos) | Delete by position |
replace(list, pos, value) | Replace by position |
member(list, value) | Find position of value |
match(list, pattern) | Find position by wildcard |
sort(list) | Sort (auto-detects type) |
setunion(list1, list2) | Set union |
setinter(list1, list2) | Set intersection |
setdiff(list1, list2) | Set difference |
Iteration
The primary iteration functions are:
iter() – evaluates an expression for each element:
[iter(apple banana cherry, strlen(##))]
Produces 5 6 6. The token ## is replaced with each element; #@ gives the 1-based position.
map() – calls a user function for each element:
[map(obj/format_item, apple banana cherry)]
filter() – keeps elements where a function returns true:
[filter(obj/is_long, apple banana cherry)]
fold() – reduces a list to a single value:
[fold(obj/sum_func, 1 2 3 4)]
Nested Lists
Since lists are just strings, nesting requires using different delimiters at each level:
red green blue|circle square triangle|small medium large
First level split on | gives three sublists; each sublist split on space gives individual elements.
An alternative is to use elements() or extract() to pull specific items from a known structure.
Performance Considerations
List operations are O(n) because lists are strings, not linked structures. Every member() or extract() call scans from the beginning of the string. For large datasets:
- Avoid nested iteration (
iter()insideiter()) on large lists. - Use
setunion()/setinter()instead of manual membership tests. - Consider storing data in separate attributes instead of one massive list.
- Use registers (
setq/setr) to avoid redundantget()calls.
Common Patterns
Building a list incrementally:
&cmd obj=$+add *:
@set me=LIST:[v(LIST)] %0;
@pemit %#=Added %0.
Processing every item:
think [iter(get(me/LIST), pemit(%#, Item: ##))]
Filtering with a condition:
think [filter(me/IS_ACTIVE, get(me/PLAYERS))]
&IS_ACTIVE me=[hasflag(%0, CONNECTED)]