# => │ │ │ │ established │ 1554 │ │
# => │ │ │ │ population │ 21650000 │ │
# => │ │ │ ╰─────────────┴──────────╯ │
# => │ 2 │ New York │ ╭─────────────┬──────────╮ │
# => │ │ │ │ established │ 1624 │ │
# => │ │ │ │ population │ 18819000 │ │
# => │ │ │ ╰─────────────┴──────────╯ │
# => ╰───┴───────────┴────────────────────────────╯
```
### Sort by key closure
Sometimes, it's useful to sort data in a more complicated manner than "increasing" or "decreasing". Instead of using `sort-by` with a cell path, you can supply a [closure](types_of_data.html#closures), which will transform each value into a [sorting key](https://en.wikipedia.org/wiki/Collation#Sort_keys) _without changing the underlying data_. Here's an example of a key closure, where we want to sort a list of assignments by their average grade:
```nu
let assignments = [
{name: 'Homework 1', grades: [97 89 86 92 89] }
{name: 'Homework 2', grades: [91 100 60 82 91] }
{name: 'Exam 1', grades: [78 88 78 53 90] }
{name: 'Project', grades: [92 81 82 84 83] }
]
$assignments | sort-by { get grades | math avg }
# => ╭───┬────────────┬───────────────────────╮
# => │ # │ name │ grades │
# => ├───┼────────────┼───────────────────────┤
# => │ 0 │ Exam 1 │ [78, 88, 78, 53, 90] │
# => │ 1 │ Project │ [92, 81, 82, 84, 83] │
# => │ 2 │ Homework 2 │ [91, 100, 60, 82, 91] │
# => │ 3 │ Homework 1 │ [97, 89, 86, 92, 89] │
# => ╰───┴────────────┴───────────────────────╯
```
The value is passed into the pipeline input of the key closure, however, you can also use it as a parameter:
```nu
let weight = {alpha: 10, beta: 5, gamma: 3}
[alpha gamma beta gamma alpha] | sort-by {|val| $weight | get $val }
# => ╭───┬───────╮
# => │ 0 │ gamma │
# => │ 1 │ gamma │
# => │ 2 │ beta │
# => │ 3 │ alpha │
# => │ 4 │ alpha │
# => ╰───┴───────╯
```
### Custom sort order
In addition to [key closures](#sort-by-key-closure), `sort-by` also supports closures which specify a custom sort order. The `--custom`, or `-c`, flag will tell `sort-by` to interpret closures as custom sort closures. A custom sort closure has two parameters, and returns a boolean. The closure should return `true` if the first parameter comes _before_ the second parameter in the sort order.
For a simple example, we could rewrite a cell path sort as a custom sort. This can be read as "If $a.size is less than $b.size, a should appear before b in the sort order":
```nu
ls | sort-by -c {|a, b| $a.size < $b.size }
# => ╭───┬─────────────────────┬──────┬──────────┬────────────────╮
# => │ # │ name │ type │ size │ modified │
# => ├───┼─────────────────────┼──────┼──────────┼────────────────┤
# => │ 0 │ my-secret-plans.txt │ file │ 100 B │ 10 minutes ago │
# => │ 1 │ shopping_list.txt │ file │ 100 B │ 2 months ago │
# => │ 2 │ myscript.nu │ file │ 1.1 KiB │ 2 weeks ago │
# => │ 3 │ bigfile.img │ file │ 10.0 MiB │ 3 weeks ago │
# => ╰───┴─────────────────────┴──────┴──────────┴────────────────╯
```
::: tip
The parameters are also passed to the custom closure as a two element list, so the following are equivalent:
- `{|a, b| $a < $b }`
- `{ $in.0 < $in.1 }`
:::
Here's an example of a custom sort which couldn't be trivially written as a key sort. In this example, we have a queue of tasks with some amount of work time and a priority. We want to sort by priority (highest first). If a task has had zero work time, we want to schedule it immediately; otherwise, we ignore the work time.
```nu
let queue = [
{task: 139, work_time: 0, priority: 1 }
{task: 52, work_time: 355, priority: 8 }
{task: 948, work_time: 72, priority: 2 }
{task: 583, work_time: 0, priority: 5 }
]
let my_sort = {|a, b|
match [$a.work_time, $b.work_time] {
[0, 0] => ($a.priority > $b.priority) # fall back to priority if equal work time
[0, _] => true, # only a has 0 work time, so a comes before b in the sort order