Skip to content

Collection

Collection · Type

A Collection is a list or dictionary with a toolkit attached: sorting, filtering, summing, grouping and more. You make one with mash.collect(...), and plenty of Foldr gives them to you ready made: a multivalue custom field, the people in a group, mash.users.get("name"), the rows of a lookup. When a script has a set of things to work on, a Collection is usually the right shape for it.

It holds an array or a dictionary. mash.collect([3, 1, 2]) is a list. mash.collect({ada: 36, bo: 29}) is a dictionary, and its keys are kept. Most methods work the same on both.

Most methods return a new Collection, so they chain. rows.where("dept", "Eng").sortByDesc("pay").pluck("name") reads left to right and leaves rows alone. A few methods change the Collection itself instead: push, put, pull, forget and pop.

Assigning doesn’t copy. set b to a gives the same Collection a second name, so b.push(1) changes a too. Use clone(a) for a copy that shares nothing.

Blocks do the custom work. filter, map, reduce, each, sortBy (with a block) and groupBy take a block that’s run once per item and returns the answer for it.

Sort and filter keep the original keys. A sorted list’s items can show their old positions as keys. Call values() to number them from 0 again.

An empty Collection is still “true”. Test emptiness with isEmpty() or count(), never with if rows.

Total and rank a list of dictionaries:

set rows to mash.collect([
{name: "Ada", dept: "Eng", pay: 50},
{name: "Bo", dept: "Ops", pay: 40},
{name: "Cy", dept: "Eng", pay: 70}
])
printline rows.sum("pay")
printline rows.sortByDesc("pay").first()["name"]
printline rows.where("dept", "Eng").pluck("name").join(", ")
160
Cy
Ada, Cy

Filter with your own test:

set n to mash.collect([5, 3, 8, 1])
set big to n.filter(block x
return x is more than 2
end)
printline big.values().join(", ")
5, 3, 8

Group and count:

set rows to mash.collect([
{name: "Ada", dept: "Eng"},
{name: "Bo", dept: "Ops"},
{name: "Cy", dept: "Eng"}
])
printline rows.groupBy("dept").map(block g
return g.count()
end)
Collection {
"Eng": 2,
"Ops": 1
}

Turn a list into a line of text, or into a plain array:

set n to mash.collect([5, 3, 8])
printline n.join("-")
printline n.all()[0]
5-3-8
5

Work through a multivalue field:

set doc to mash.files.get("Claims", "N1 Claim Form.pdf")
set parties to mash.collect(doc.fields["Party"] ?? [])
printline parties.join("; ")
  • join and implode are the same. Both write the items with a separator between.
  • Don’t change a Collection while you loop over it. Collect what to change, then change it.
  • count() and isEmpty() for emptiness, because a Collection is always “true”.
  • A method name that doesn’t exist raises an error rather than doing nothing. If a call fails with “does not exist”, check the generated list below.

Collections and Blocks in the tutorial, and Values and types.

A list with methods, which mash.collect() returns. A plain list or dictionary answers the same methods, so [3, 1, 2].sort() and mash.collect([3, 1, 2]).sort() do the same thing. Where PHP wants a function, MaSH takes a block: items.map(block(item) { return item.size }). Only a block is accepted there, never the name of a PHP function. The methods that change the list are marked.

Changes the value
collection.add(item: mixed)

Adds an item to the end. On a list or dictionary held in a variable it changes that variable in place: list.push(3) is enough, there is no need to assign the result.

collection.all()

Returns the items as a plain list or dictionary.

collection.average(callback?: mixed)

The same as avg.

collection.avg(callback?: mixed)

The average of the numbers, or of one field of each item: avg(“price”).

collection.chunk(size: mixed)

Splits the items into groups of the size you give. The last group may be smaller.

collection.collapse()

Joins a list of lists into one flat list.

collection.combine(values: mixed)

Uses the items as keys and the list you give as their values, and returns the dictionary.

collection.concat(source: mixed)

Adds the items of another list to the end.

collection.contains(key: mixed, operator?: mixed, value?: mixed)

True when a value is in it. With a block, true when the block returns true for any item.

collection.count() → int

The number of items.

collection.countBy(countBy?: mixed)

Counts how often each value turns up. With a block, counts by what the block returns.

collection.diff(items: mixed)

The items that are not in the other list.

collection.diffKeys(items: mixed)

The items whose keys are not in the other dictionary.

collection.doesntContain(key: mixed, operator?: mixed, value?: mixed)

True when a value is not in it. With a block, true when the block returns true for no item.

collection.duplicates(callback?: mixed, strict?: mixed)

The values that appear more than once.

collection.each(callback: block)

Runs the block on each item. Return false from it to stop.

collection.every(key: mixed, operator?: mixed, value?: mixed)

True when the block returns true for every item.

collection.except(keys: mixed)

Everything except the keys you name.

collection.filter(callback?: block)

Keeps the items the block returns true for. With no block, drops empty values.

collection.first(callback?: block, default?: mixed)

The first item. With a block, the first item the block returns true for.

collection.firstWhere(key: mixed, operator?: mixed, value?: mixed)

The first item whose field has the value: firstWhere(“type”, “pdf”).

collection.flatMap(callback: block)

Runs the block on each item, then flattens the results one level.

collection.flatten(depth?: mixed)

Flattens nested lists into one.

collection.flip()

Swaps the keys and the values.

Changes the value
collection.forget(keys: mixed)

Removes the item at a key. On a list or dictionary held in a variable it changes that variable in place: list.push(3) is enough, there is no need to assign the result.

collection.get(key: mixed, default?: mixed)

The value at a key, or the default you give when it is not there.

collection.groupBy(groupBy: mixed, preserveKeys?: mixed)

Groups the items by a field, or by what the block returns, into a dictionary of lists.

collection.has(key: mixed)

True when the key exists.

collection.implode(value: mixed, glue?: mixed)

Joins the values into one string with the separator you give.

collection.intersect(items: mixed)

Keeps only the items that are also in the other list.

collection.intersectByKeys(items: mixed)

Keeps only the items whose keys are also in the other dictionary.

collection.isEmpty()

True when there are no items.

collection.isNotEmpty()

True when there is at least one item.

collection.join(glue: mixed, finalGlue?: mixed)

Joins the values into a string, with an optional different separator before the last.

collection.keyBy(keyBy: mixed)

Re-keys the items by a field, or by what the block returns.

collection.keys()

The keys.

collection.last(callback?: block, default?: mixed)

The last item. With a block, the last item the block returns true for.

collection.map(callback: block)

Runs the block on each item and returns the results.

collection.mapWithKeys(callback: block)

Runs the block on each item. The block returns a one-entry dictionary, and they are merged into one.

collection.max(callback?: mixed)

The largest value, or the largest of one field.

collection.median(key?: mixed)

The middle value, or the middle of one field.

collection.merge(items: mixed)

Adds the items of another dictionary or list. A key that exists is overwritten.

collection.mergeRecursive(items: mixed)

Like merge, but a key that exists in both and holds a list has the two lists joined.

collection.min(callback?: mixed)

The smallest value, or the smallest of one field.

collection.only(keys: mixed)

Keeps only the keys you name.

collection.pad(size: mixed, value: mixed)

Fills the list with a value up to a size. A negative size pads at the start.

collection.partition(key: mixed, operator?: mixed, value?: mixed)

Splits the items into two lists: those the block returns true for, and the rest.

collection.pluck(value: mixed, key?: mixed)

The value of one field from each item: pluck(“name”).

Changes the value
collection.prepend(value: mixed, key?: mixed)

Adds an item to the start. On a list or dictionary held in a variable it changes that variable in place: list.push(3) is enough, there is no need to assign the result.

Changes the value
collection.push(values?: mixed)

Adds an item to the end. On a list or dictionary held in a variable it changes that variable in place: list.push(3) is enough, there is no need to assign the result.

Changes the value
collection.put(key: mixed, value: mixed)

Sets the item at a key. On a list or dictionary held in a variable it changes that variable in place: list.push(3) is enough, there is no need to assign the result.

collection.random(number?: mixed, preserveKeys?: mixed)

A random item. Give a number to get that many.

collection.reduce(callback: block, initial?: mixed)

Runs the block on each item with the running result, and returns the final result.

collection.reject(callback?: mixed)

Drops the items the block returns true for.

Changes the value
collection.remove(keys: mixed)

Removes the item at a key. On a list or dictionary held in a variable it changes that variable in place: list.push(3) is enough, there is no need to assign the result.

collection.reverse()

The items in the opposite order.

collection.search(value: mixed, strict?: mixed)

The key of the first item with the value (or that the block returns true for), or false.

collection.shuffle(seed?: mixed)

The items in a random order.

collection.skip(count: mixed)

Everything after the first n items.

collection.slice(offset: mixed, length?: mixed)

A part of the list, from an offset, with an optional length.

collection.sort(callback?: mixed)

Sorted low to high. With a block, the block compares two items.

collection.sortBy(callback: mixed, options?: mixed, descending?: mixed)

Sorted by a field, or by what the block returns, low to high.

collection.sortByDesc(callback: mixed, options?: mixed)

Sorted by a field, or by what the block returns, high to low.

collection.sortDesc(options?: mixed)

Sorted high to low.

collection.sortKeys(options?: mixed, descending?: mixed)

Sorted by key, low to high.

collection.sortKeysDesc(options?: mixed)

Sorted by key, high to low.

collection.sum(callback?: mixed)

The total of the numbers, or of one field of each item.

collection.take(limit: mixed)

The first n items. A negative n takes from the end.

collection.toArray()

Returns the items as a plain list or dictionary.

collection.unique(key?: mixed, strict?: mixed)

Drops repeated values. Give a field to compare by.

collection.values()

The values, with the keys replaced by 0, 1, 2 and so on.

collection.where(key: mixed, operator?: mixed, value?: mixed)

Keeps the items whose field matches: where(“size”, ”>”, 100), or where(“type”, “pdf”).

collection.whereIn(key: mixed, values: mixed, strict?: mixed)

Keeps the items whose field is one of the values you give.

collection.whereNotIn(key: mixed, values: mixed, strict?: mixed)

Keeps the items whose field is none of the values you give.

collection.zip(items: mixed)

Pairs each item with the item at the same place in another list.