Home Explore Blog CI



nushell

3rd chunk of `book/sorting.md`
77f8346e2cb20853946a6cd056d6afb0ab7365d7d5c141bf000000010000144e
# => │   │           │ │ 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

Title: Custom Sorting in Nushell with Key Closures and Custom Sort Orders
Summary
This section further explains sorting in Nushell using key closures and custom sort orders. It shows how to use closures to transform values into sorting keys for more complex sorting scenarios. It also introduces custom sort closures, which allow specifying a custom comparison logic between two elements to determine their sort order, using the `-c` flag. It demonstrates examples of rewriting cell path sorts as custom sorts and handling more complex sorting scenarios based on multiple conditions.