You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: book/sorting.md
+249-2Lines changed: 249 additions & 2 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -4,6 +4,8 @@ Nushell offers many ways of sorting data, and which method you reach for will de
4
4
5
5
## Basic sorting
6
6
7
+
### Lists
8
+
7
9
Sorting a basic list works exactly how you might expect:
8
10
9
11
```nu
@@ -21,7 +23,7 @@ Sorting a basic list works exactly how you might expect:
21
23
However, things get a bit more complex when you start combining types. For example, let's see what happens when we have a list with numbers _and_ strings:
22
24
23
25
```nu
24
-
> ["foobar" 4 9 2 1 "hello" 8 6] | sort
26
+
> ["hello" 4 9 2 1 "foobar" 8 6] | sort
25
27
╭───┬────────╮
26
28
│ 0 │ 1 │
27
29
│ 1 │ 2 │
@@ -40,6 +42,251 @@ We can see that the numbers are sorted in order, and the strings are sorted to t
40
42
If you _do_ want a sort containing differing types to error, see [strict sort](#strict-sort).
41
43
:::
42
44
43
-
## Custom sorts
45
+
Nushell's sort is also **stable**, meaning equal values will retain their original ordering relative to each other. This is illustrated here using the [insensitive](#insensitive-sort) sort option:
46
+
47
+
```nu
48
+
> ["foo" "FOO" "BAR" "bar"] | sort -i
49
+
╭───┬─────╮
50
+
│ 0 │ BAR │
51
+
│ 1 │ bar │
52
+
│ 2 │ foo │
53
+
│ 3 │ FOO │
54
+
╰───┴─────╯
55
+
```
56
+
57
+
Since this sort is case insensitive, `foo` and `FOO` are considered equal to each other, and the same is true for `bar` and `BAR`. In the result, the uppercase `BAR` precedes the lowercase `bar`, since the uppercase `BAR` also precedes the lowercase `bar` in the input. Similarly, the lowercase `foo` precedes the uppercase `FOO` in both the input and the result.
58
+
59
+
### Records
60
+
61
+
Records can be sorted two ways: by key, and by value. By default, passing a record to `sort` will sort in order of its keys:
62
+
63
+
```nu
64
+
{x: 123, a: hello!, foo: bar} | sort
65
+
╭─────┬────────╮
66
+
│ a │ hello! │
67
+
│ foo │ bar │
68
+
│ x │ 123 │
69
+
╰─────┴────────╯
70
+
```
71
+
72
+
To instead sort in order of values, use the `-v` flag:
73
+
74
+
```nu
75
+
{x: 123, a: hello! foo: bar} | sort -v
76
+
╭─────┬────────╮
77
+
│ x │ 123 │
78
+
│ foo │ bar │
79
+
│ a │ hello! │
80
+
╰─────┴────────╯
81
+
```
82
+
83
+
### Tables
84
+
85
+
Table rows are sorted by comparing rows by the columns in order. If two rows have equal values in their first column, they are sorted by their second column. This repeats until the rows are sorted different or all columns are equal.
86
+
87
+
```nu
88
+
> let items = [
89
+
{id: 100, price: 10, quantity: 5 }
90
+
{id: 100, price: 5, quantity: 8 }
91
+
{id: 100, price: 5, quantity: 1 }
92
+
]
93
+
> $items | sort
94
+
╭───┬─────┬───────┬──────────╮
95
+
│ # │ id │ price │ quantity │
96
+
├───┼─────┼───────┼──────────┤
97
+
│ 0 │ 100 │ 5 │ 1 │
98
+
│ 1 │ 100 │ 5 │ 8 │
99
+
│ 2 │ 100 │ 10 │ 5 │
100
+
╰───┴─────┴───────┴──────────╯
101
+
```
102
+
103
+
In this example, the `id` column for all items is equal. Then, the two items with price `5` are sorted before the item with price `10`. Finally, the `item` with quantity `1` is sorted before the item with quantity `8`.
104
+
105
+
## Sorting structured data
106
+
107
+
### Cell path
108
+
109
+
In order to sort more complex types, such as tables, you can use the `sort-by` command. `sort-by` can order its input by a [cell path](navigating_structured_data.html#cell-paths).
We can also provide multiple cell paths to `sort-by`, which will sort by each cell path in order of priority. You can think of providing multiple cell paths as a "tiebreaker" for elements which have equal values. Let's sort first by size, then by modification time:
This time, `shopping_list.txt` comes before `my-secret-plans.txt`, since it has an earlier modification time, but two larger files remain sorted after the `.txt` files.
140
+
141
+
Furthermore, we use more complex cell paths to sort nested data:
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:
171
+
172
+
```nu
173
+
> let assignments = [
174
+
{name: 'Homework 1', grades: [97 89 86 92 89] }
175
+
{name: 'Homework 2', grades: [91 100 60 82 91] }
176
+
{name: 'Exam 1', grades: [78 88 78 53 90] }
177
+
{name: 'Project', grades: [92 81 82 84 83] }
178
+
]
179
+
> $assignments | sort-by { get grades | math avg }
180
+
╭───┬────────────┬───────────────────────╮
181
+
│ # │ name │ grades │
182
+
├───┼────────────┼───────────────────────┤
183
+
│ 0 │ Exam 1 │ [78, 88, 78, 53, 90] │
184
+
│ 1 │ Project │ [92, 81, 82, 84, 83] │
185
+
│ 2 │ Homework 2 │ [91, 100, 60, 82, 91] │
186
+
│ 3 │ Homework 1 │ [97, 89, 86, 92, 89] │
187
+
╰───┴────────────┴───────────────────────╯
188
+
```
189
+
190
+
The value is passed into the pipeline input of the key closure, however you can also use it as a parameter:
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.
209
+
210
+
For a simple example, we could rewrite a cell path sort as a custom sort:
The parameters are also passed to the custom closure as a two element list, so the following are equivalent:
226
+
227
+
-`{|a, b| $a < $b }`
228
+
-`{ $in.0 < $in.1 }`
229
+
:::
230
+
231
+
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), but if a task has had zero work time, we want to schedule it immediately. Otherwise, we ignore the work time.
232
+
233
+
```nu
234
+
> let queue = [
235
+
{task: 139, work_time: 0, priority: 1 }
236
+
{task: 52, work_time: 355, priority: 8 }
237
+
{task: 948, work_time: 72, priority: 2 }
238
+
{task: 583, work_time: 0, priority: 5 }
239
+
]
240
+
> let my_sort = {|a, b|
241
+
if ($a.work_time == 0) {
242
+
true
243
+
} else if ($b.work_time == 0) {
244
+
false
245
+
} else {
246
+
$a.priority > $b.priority
247
+
}
248
+
}
249
+
> $queue | sort-by -c $my_sort
250
+
╭───┬──────┬───────────┬──────────╮
251
+
│ # │ task │ work_time │ priority │
252
+
├───┼──────┼───────────┼──────────┤
253
+
│ 0 │ 583 │ 0 │ 5 │
254
+
│ 1 │ 139 │ 0 │ 1 │
255
+
│ 2 │ 52 │ 355 │ 8 │
256
+
│ 3 │ 948 │ 72 │ 2 │
257
+
╰───┴──────┴───────────┴──────────╯
258
+
```
44
259
45
260
### Strict sort
261
+
262
+
Custom sort closures also provide a simple way to sort data while enforcing type homogeneity. This takes advantage of [operators requiring compatible data types](operators.html#types):
263
+
264
+
```nu
265
+
> let data = ["hello" 4 9 2 1 "foobar" 8 6]
266
+
> $data | sort-by -c {|a, b| $a < $b}
267
+
Error: nu::shell::type_mismatch
268
+
269
+
× Type mismatch during operation.
270
+
╭─[entry #173:1:28]
271
+
1 │ $data | sort-by -c {|a, b| $a < $b}
272
+
· ─┬ ┬ ─┬
273
+
· │ │ ╰── string
274
+
· │ ╰── type mismatch for operator
275
+
· ╰── int
276
+
╰────
277
+
278
+
```
279
+
280
+
::: warning
281
+
This does not currently work with `null` values due to comparison between any value and `null` returning `null`.
282
+
:::
283
+
284
+
## Special sorts
285
+
286
+
### Insensitive sort
287
+
288
+
### Natural sort
289
+
290
+
### Sorting with mixed types
291
+
292
+
Under some circumstances, you might end up with values containing mixed types.
0 commit comments