Skip to content
Open Saka

Transforming Bags

A pipeline passes a Bag through a series of steps, read from left to right. These examples use this Flow of sales:

def sales = {
(category: "a", amount: 2)
(category: "a", amount: 3)
(category: "b", amount: 4)
(category: "b", amount: 1)
}

map runs for each occurrence. Inside it, . is the current Value:

def amounts = sales map .amount
amounts // {1, 2, 3, 4}

You can name that Value instead:

def doubled = sales map sale => sale.amount * 2
doubled // {2, 4, 6, 8}

if keeps Values that pass a test:

def larger_sales = sales if .amount > 1
larger_sales
// {
// (amount: 2, category: "a")
// (amount: 3, category: "a")
// (amount: 4, category: "b")
// }

agg runs once on the whole Bag. Here .category reads every category and % removes repeats:

def categories = sales agg .category%
categories // {"a", "b"}

match chooses the first matching arm. Each arm lists Values, then ~> and a result. _ matches anything left:

def sizes = sales map .amount match {
1 ~> "single"
{2, 3} ~> "few"
_ ~> "many"
}
sizes // {"few"'2, "many", "single"}

The arms must cover every possible input. Use then … else for a Boolean choice.

to uses the input as the key and the computed result as the value:

def successors = {1, 2} to . + 1
successors // {1 -> 2, 2 -> 3}

by uses the computed result as the key and the input as the value:

def sales_by_category = sales by .category
sales_by_category
// {
// "a" -> (amount: 2, category: "a")
// "a" -> (amount: 3, category: "a")
// "b" -> (amount: 1, category: "b")
// "b" -> (amount: 4, category: "b")
// }

Repeated keys stay separate. The next page groups them.

Form Works on Result
X map K Each Value Results of K
X if P Each Value Values that pass P
X agg K The whole Bag Result of K
X to K Each Value Input -> result
X by K Each Value Result -> input
X match {S ~> K} Each Value Result of the first matching arm