Marrow picks a sort by input type and size: for primitive arrays, a pattern-defeating quicksort for small inputs and an LSD radix sort for large ones; a comparison sort for strings; a counting sort for booleans. Nulls are ordered explicitly — you choose whether they sort to the front or the back.
Sorting an array
mc.sort returns a sorted copy; the array’s .argsort() method (or mc.sort_indices) returns the indices that would sort it (an int32 array), leaving the input untouched:
sort and sort_indices take a sort_keys sequence of (column, order) pairs — for a plain array the column name is ignored, the first key’s direction is used, and more than one key raises NotImplementedError — and a null_placement keyword argument:
Sorting works across types — strings order lexicographically:
words = ma.array(["pear", "apple", None, "cherry"])print(mc.sort(words, null_placement="at_end"))
StringArray([apple, cherry, pear, NULL])
Sorting a table
RecordBatch.sort_by reorders whole rows by a key column. Pass a list of (column, "ascending" | "descending") tuples and a null-placement argument (None for the default):
sort_by also accepts a num_threads argument (0 auto-selects cores, 1 forces the serial path) for large batches.
Under the hood — the Mojo sort kernel
At the Mojo level, sort_indices returns the permutation for a single array and take applies it to get a sorted copy. Both take a type-erased DynArray; call SortIndices.apply / TakeKernel.apply when you already hold a typed array.
from marrow.kernels.sort import sort_indicesfrom marrow.kernels.filter import takefrom marrow.builders import arrayfrom marrow.dtypes import int64var values =array([3, 1, 4, 1, 5, 9, 2, 6], int64)# Indices that would sort the arrayvar idx =sort_indices(values.copy(), ascending=True, nulls_first=True)# A sorted copyvar ordered =take(values.copy(), idx)
Multi-column sort operates on a StructArray, ordering rows by a list of key column indices with a per-key ascending flag:
from marrow.kernels.sort import sort# rows sorted by column 0 ascending, ties broken by column 1 descendingvar ordered =sort(struct_array, key_indices=[0, 1], ascending=[True, False])
Algorithm selection
For primitive arrays, the strategy switches at fixed sizes:
Input size
Strategy
N < 32,768
PDQsort (pattern-defeating quicksort)
N ≥ 32,768
LSD radix sort
N ≥ 524,288
Parallel radix sort, given a multi-threaded context
The thresholds are fixed rather than tuned per machine, and they are not the fastest choice at every size. mc.sort and mc.sort_indices run single-threaded unless you pass a multi-threaded ctx.