Package

lists

List utilities beyond the builtins: windows, splits, grouping, zips, set operations, combinatorics, searching and safe index edits

0.1.0 MIT

Install

sspur add lists@^0.1.0

or in sspur.toml:

lists = { version = "^0.1.0" }

README

lists

List utilities for SSPUR that the builtin List methods don't cover: splitting and sliding windows, run grouping, counting into maps, zips of every shape, order-preserving set and multiset operations, combinatorics with a safety limit, binary search by key, and index edits that never trap. It is the SSPUR counterpart of Guava's Lists/Iterables, Python's itertools and more-itertools, and lodash's array functions.

Every function is pure and generic. A function that takes a lambda performs whatever the lambda performs (f: A -> B ! e), so you can pass logging or failing functions. Out-of-range indexes and counts never trap: each function says what it does with them (usually clamping, or returning the list unchanged). The combinatoric functions have a pre clause that limits their output to combinatorics_limit() (1,000,000) lists.

Example

use lists.{chunk_by, top_k, sliding, combinations, index_by, split_on}

type Order = {id: Int, customer: Str, cents: Int} derive Eq, Show

fn main() -> Unit ! log
= do
  orders = [Order{id: 1, customer: "ana", cents: 1200}, Order{id: 2, customer: "ana", cents: 300}, Order{id: 3, customer: "bo", cents: 4500}, Order{id: 4, customer: "cy", cents: 800}]
  log(top_k(orders, 2, _.cents).map(_.id).str)
  log(chunk_by(orders, _.customer).map(g => "{g.0}: {g.1.len}").join(", "))
  log(index_by(orders, _.id).get(3).map(_.customer).str)
  log(sliding([1, 2, 3, 4, 5], 2, 2, true).str)
  log(combinations(["a", "b", "c"], 2).str)
  log(split_on(["x", "", "y", "z", ""], "").str)
  log(lists.cartesian([1, 2], ["s", "m"]).str)

Output (the same natively and with --interp):

[3, 1]
ana: 2, bo: 1, cy: 1
some("bo")
[[1, 2], [3, 4], [5]]
[["a", "b"], ["a", "c"], ["b", "c"]]
[["x"], ["y", "z"], []]
[(1, "s"), (1, "m"), (2, "s"), (2, "m")]

API

Each function has a doc comment with its exact edge-case behaviour; sspur api lists them.

Splitting and windows

FunctionWhat it does
split_at(xs, i)(take(i), drop(i)), i clamped
split_while(xs, p), split_until(xs, p)Haskell's span and break
split_when(xs, p)split between neighbours where p(a, b) holds
split_on(xs, sep), split_where(xs, p)split at separators, dropping them, like Str.split
split_parts(xs, n)exactly n parts of nearly equal length
sliding(xs, size, step, partial)windows with a step, optionally keeping shortened tail windows
chunks_padded(xs, n, fill)chunks with the last chunk padded
chunk_by(xs, key)runs of equal keys, with the key
rle(xs), rle_decode(runs)run-length encoding
tails(xs), inits(xs)all suffixes, all prefixes
take_last, drop_last, take_last_while, drop_last_whilethe end of a list
pad_to(xs, n, fill), pad_front_to(xs, n, fill)pad to a minimum length

Duplicates

FunctionWhat it does
dedup(xs), dedup_by(xs, key)collapse runs of equal neighbours
distinct_by(xs, key)first element per key
duplicates(xs)values that occur more than once
all_equal(xs), all_distinct(xs)uniformity checks
single(xs)the only element, if there is exactly one

Counting and grouping

FunctionWhat it does
frequencies(xs)Map of value to count
count_by(xs, key), count_where(xs, p)counts by key, or matching a predicate
index_by(xs, key)Map of key to element, the last wins
associate(xs, f)Map from the pairs f gives, the last wins
group_into(xs, key)Map of key to its elements in input order

Aggregates

FunctionWhat it does
sum_by(xs, f), sum_by_f64(xs, f)sums, the float one compensated (Kahan-Babuska)
min_by, max_by, min_max, min_max_byextremes, the first among equals
top_k(xs, k, key), bottom_k(xs, k, key)the k best by key, stable
largest(xs, k), smallest(xs, k)the k largest or smallest elements

Combining

FunctionWhat it does
interleave(xs, ys), interleave_all(xss)alternate elements, round-robin over many lists
intersperse(xs, sep), intercalate(xss, sep)separators between elements or lists
zip3, zip_with, zip_longest, zip_longest_optzips of three lists, with a function, or to the longer length
unzip(ps), unzip3(ts)split pairs and triples
transpose(rows)rows to columns, ragged rows allowed
pairwise(xs)adjacent pairs

Combinatorics

FunctionWhat it does
cartesian(xs, ys), cartesian_all(xss)cartesian products
permutations(xs, k), combinations(xs, k), combinations_with_replacement(xs, k)in lexicographic order of positions, as in itertools
power_set(xs)every sublist, by size; at most 20 elements
count_permutations(n, k), count_combinations(n, k)exact counts, none when they don't fit an Int
combinatorics_limit()the output limit, 1,000,000

Building and mapping

FunctionWhat it does
replicate(x, n), cycle(xs, n), cycle_take(xs, n)repetition
map_indexed(xs, f), filter_indexed(xs, p)with the index
filter_map(xs, f), compact(xs), find_map(xs, f)working with Opt
partition_map(xs, f), partition_results(rs)split oks from errs
sequence_opt(xs), sequence_res(rs)all or nothing

Index edits (never trap)

FunctionWhat it does
at(xs, i)element with negative indexes from the end
insert_at, insert_all_atinsert, the index clamped
remove_at, remove_firstremove by index or the first equal element
set_at, update_atreplace one element
swap(xs, i, j), move_item(xs, from, to)reorder

Searching

FunctionWhat it does
find_last, find_last_index, last_index_ofsearch from the end
indices_where(xs, p), indices_of(xs, x)every matching index
partition_point(xs, p)binary search for the end of the p prefix
lower_bound_by, upper_bound_by, binary_search_bybinary search by key
insert_sorted(xs, x), insert_sorted_by(xs, x, key)stable sorted insertion
index_of_sublist, last_index_of_sublist, contains_sublistcontiguous sublists
has_prefix, has_suffixstarts_with and ends_with for lists
count_sublist, replace_sublistnon-overlapping occurrences, left to right

Folds and order

FunctionWhat it does
fold_right, reduce, reduce_right, scan_rightright folds and folds without a start value
is_sorted, is_strictly_sorted, is_sorted_by, is_sorted_withsortedness by Ord, key or comparator
argsort, argsort_by, ranks, dense_rankssorting permutations and ranks
compare_lists(xs, ys)lexicographic comparison
merge_by(xs, ys, key), merge_all(xss)stable merges of sorted lists

Functions with an Ord bound use the type's Ord impl, so a hand-written order (a descending wrapper, say) is respected.

Set and multiset operations

FunctionWhat it does
union, intersect, difference, sym_differencedistinct results in first-seen order
contains_all, contains_any, is_disjointmembership
multi_intersect, multi_difference, multi_unionkeeping duplicates by count, in input order
is_permutation(xs, ys)the same elements with the same counts

Random

FunctionWhat it does
sample(xs, k, seed), sample_ordered(xs, k, seed)k distinct positions, pure in the seed like the builtin shuffle

Out of scope

  • Lazy and infinite sequences: the standard library's View (xs.view, iota, iterate, take_while, chain) and generators (yield) cover them, so everything here is eager.
  • What the builtins already do: chunks, windows, partition, scan, flatten, take_while, drop_while, rotate, binary_search, lower_bound, upper_bound, group_by, counts, merge, next_perm, unique, shuffle, choice, slice, find_index, index_of, zip, enumerate.
  • Statistics (mean, median, percentiles) belong to a numbers package; maps of maps to a maps package.
  • Mutable, in-place algorithms (nth_element, in-place sorts): SSPUR lists are immutable values.
  • Weighted sampling and random distributions: use the builtin rand_weighted and Rng.

Performance notes: index-based results are built with map, filter and flat_map, so they are linear in both tiers. index_of_sublist and friends are naive (O(n * m) in the worst case). In the interpreter, tails and inits copy each suffix and prefix.

Install

sspur add lists

MIT licensed.

API

split_at fn

fn split_at[A](xs: List[A], i: Int) -> (List[A], List[A])

(xs.take(i), xs.drop(i)) with i clamped to 0..=xs.len: a negative i gives ([], xs) and an i past the end gives (xs, []).

split_while fn

fn split_while[A, e](xs: List[A], p: A -> Bool ! e) -> (List[A], List[A]) ! e

The longest prefix whose elements all satisfy p, and the rest (Haskell's span). p is called once per element of the prefix, plus once for the first element that fails.

split_until fn

fn split_until[A, e](xs: List[A], p: A -> Bool ! e) -> (List[A], List[A]) ! e

The longest prefix with no element satisfying p, and the rest, which starts with the first element that does (Haskell's break).

split_when fn

fn split_when[A, e](xs: List[A], p: (A, A) -> Bool ! e) -> List[List[A]] ! e

Splits xs between every pair of neighbours a, b for which p(a, b) holds; no element is lost. An empty list gives []. split_when([1, 2, 4, 5], (a, b) => b != a + 1) is [[1, 2], [4, 5]].

split_on fn

fn split_on[A](xs: List[A], sep: A) -> List[List[A]]

Splits xs at every element equal to sep, dropping the separators, like Str.split: [] gives [[]], and neighbouring or trailing separators give empty pieces, so the result always has one more piece than there are separators.

split_where fn

fn split_where[A, e](xs: List[A], p: A -> Bool ! e) -> List[List[A]] ! e

split_on with a predicate: splits at every element satisfying p and drops those elements.

split_parts fn

fn split_parts[A](xs: List[A], n: Int where _ >= 1) -> List[List[A]]

Exactly n consecutive parts whose lengths differ by at most one, the longer parts first (more-itertools' divide). With fewer than n elements the last parts are empty.

sliding fn

fn sliding[A](xs: List[A], size: Int where _ >= 1, step: Int where _ >= 1, partial: Bool) -> List[List[A]]

Windows of size elements starting every step elements (Kotlin's windowed). With partial false only full windows are returned; with partial true the windows that start before the end but run past it are kept, shortened. sliding(xs, n, 1, false) is xs.windows(n) and sliding(xs, n, n, true) is xs.chunks(n).

chunks_padded fn

fn chunks_padded[A](xs: List[A], n: Int where _ >= 1, fill: A) -> List[List[A]]

xs.chunks(n) with the last chunk padded with fill to n elements. An empty list gives [].

chunk_by fn

fn chunk_by[A, K, e](xs: List[A], key: A -> K ! e) -> List[(K, List[A])] ! e

Groups runs of consecutive elements with the same key, each with its key (Python's itertools.groupby, Rust's chunk_by). key is called once per element. Equal keys that are not adjacent make separate runs; use group_into to group them all.

rle fn

fn rle[A](xs: List[A]) -> List[(A, Int)]

Run-length encoding: each run of equal neighbours as (value, length).

rle_decode fn

fn rle_decode[A](runs: List[(A, Int)]) -> List[A]

The inverse of rle; counts below 1 contribute nothing.

tails fn

fn tails[A](xs: List[A]) -> List[List[A]]

Every suffix of xs, longest first, ending with []: xs.len + 1 lists.

inits fn

fn inits[A](xs: List[A]) -> List[List[A]]

Every prefix of xs, shortest first, starting with []: xs.len + 1 lists.

take_last fn

fn take_last[A](xs: List[A], n: Int) -> List[A]

The last n elements (all of them when n >= xs.len, none when n <= 0).

drop_last fn

fn drop_last[A](xs: List[A], n: Int) -> List[A]

xs without its last n elements ([] when n >= xs.len, xs when n <= 0).

take_last_while fn

fn take_last_while[A, e](xs: List[A], p: A -> Bool ! e) -> List[A] ! e

The longest suffix whose elements all satisfy p, tested from the end.

drop_last_while fn

fn drop_last_while[A, e](xs: List[A], p: A -> Bool ! e) -> List[A] ! e

xs without the longest suffix whose elements all satisfy p (an rstrip for lists).

pad_to fn

fn pad_to[A](xs: List[A], n: Int, fill: A) -> List[A]

xs padded at the end with fill to at least n elements; longer lists are unchanged.

pad_front_to fn

fn pad_front_to[A](xs: List[A], n: Int, fill: A) -> List[A]

xs padded at the front with fill to at least n elements; longer lists are unchanged.

dedup fn

fn dedup[A](xs: List[A]) -> List[A]

xs with runs of equal neighbours collapsed to their first element (Unix uniq). Use the builtin unique to drop every repeat.

dedup_by fn

fn dedup_by[A, K, e](xs: List[A], key: A -> K ! e) -> List[A] ! e

dedup comparing keys: keeps the first element of each run of neighbours with equal keys.

distinct_by fn

fn distinct_by[A, K, e](xs: List[A], key: A -> K ! e) -> List[A] ! e

The first element for each distinct key, in input order (lodash's uniqBy). key is called once per element.

duplicates fn

fn duplicates[A](xs: List[A]) -> List[A]

The values that occur more than once, each once, in the order of their first occurrence.

all_equal fn

fn all_equal[A](xs: List[A]) -> Bool

Whether every element equals the first (true for an empty list).

all_distinct fn

fn all_distinct[A](xs: List[A]) -> Bool

Whether no two elements are equal (true for an empty list).

single fn

fn single[A](xs: List[A]) -> Opt[A]

The only element of xs, or none when it has zero or several.

frequencies fn

fn frequencies[A](xs: List[A]) -> Map[A, Int]

How many times each value occurs (Python's Counter). The builtin counts gives the same numbers as a list in first-seen order.

count_by fn

fn count_by[A, K, e](xs: List[A], key: A -> K ! e) -> Map[K, Int] ! e

How many elements have each key (lodash's countBy).

count_where fn

fn count_where[A, e](xs: List[A], p: A -> Bool ! e) -> Int ! e

How many elements satisfy p.

index_by fn

fn index_by[A, K, e](xs: List[A], key: A -> K ! e) -> Map[K, A] ! e

A map from each element's key to the element (lodash's keyBy). When several elements share a key the last one wins; use group_into to keep them all.

associate fn

fn associate[A, K, V, e](xs: List[A], f: A -> (K, V) ! e) -> Map[K, V] ! e

A map built from the (key, value) pair f gives for each element (Kotlin's associate). When keys repeat the last pair wins.

group_into fn

fn group_into[A, K, e](xs: List[A], key: A -> K ! e) -> Map[K, List[A]] ! e

The elements grouped by key into a map; each group keeps input order. The builtin group_by gives the same groups as a list in first-seen key order.

sum_by fn

fn sum_by[A, e](xs: List[A], f: A -> Int ! e) -> Int ! e

The sum of f over the elements (0 for an empty list); overflow traps like +.

sum_by_f64 fn

fn sum_by_f64[A, e](xs: List[A], f: A -> F64 ! e) -> F64 ! e

The sum of f over the elements as floats (0.0 for an empty list), with Kahan-Babuska compensation, so long sums of small terms lose no precision to a large running total.

min_by fn

fn min_by[A, K: Ord, e](xs: List[A], key: A -> K ! e) -> Opt[A] ! e

The first element with the smallest key, or none for an empty list. key is called once per element.

max_by fn

fn max_by[A, K: Ord, e](xs: List[A], key: A -> K ! e) -> Opt[A] ! e

The first element with the largest key, or none for an empty list. key is called once per element.

min_max fn

fn min_max[T: Ord](xs: List[T]) -> Opt[(T, T)]

The smallest and the largest element in one pass (the first of each among equals), or none for an empty list.

min_max_by fn

fn min_max_by[A, K: Ord, e](xs: List[A], key: A -> K ! e) -> Opt[(A, A)] ! e

min_by and max_by in one pass: the first element with the smallest key and the first with the largest, or none for an empty list.

top_k fn

fn top_k[A, K: Ord, e](xs: List[A], k: Int, key: A -> K ! e) -> List[A] ! e

The k elements with the largest keys, largest first; equal keys keep input order, so the result is stable. k <= 0 gives [] and k >= xs.len sorts the whole list.

bottom_k fn

fn bottom_k[A, K: Ord, e](xs: List[A], k: Int, key: A -> K ! e) -> List[A] ! e

The k elements with the smallest keys, smallest first, stable like top_k.

largest fn

fn largest[T: Ord](xs: List[T], k: Int) -> List[T]

The k largest elements, largest first (Python's heapq.nlargest).

smallest fn

fn smallest[T: Ord](xs: List[T], k: Int) -> List[T]

The k smallest elements, smallest first (Python's heapq.nsmallest).

interleave fn

fn interleave[A](xs: List[A], ys: List[A]) -> List[A]

Alternates elements of xs and ys, starting with xs; the rest of the longer list follows.

interleave_all fn

fn interleave_all[A](xss: List[List[A]]) -> List[A]

Round-robin over any number of lists: the first element of each, then the second of each, skipping lists that have run out (more-itertools' interleave_longest).

intersperse fn

fn intersperse[A](xs: List[A], sep: A) -> List[A]

sep between every two elements: [a, sep, b, sep, c].

intercalate fn

fn intercalate[A](xss: List[List[A]], sep: List[A]) -> List[A]

The lists of xss joined with sep between every two (join for lists of lists).

zip3 fn

fn zip3[A, B, C](xs: List[A], ys: List[B], zs: List[C]) -> List[(A, B, C)]

Triples of the elements at the same index, as long as the shortest list.

zip_with fn

fn zip_with[A, B, C, e](xs: List[A], ys: List[B], f: (A, B) -> C ! e) -> List[C] ! e

f applied to the elements at the same index, as long as the shorter list.

zip_longest fn

fn zip_longest[A, B](xs: List[A], ys: List[B], fill_a: A, fill_b: B) -> List[(A, B)]

Pairs as long as the longer list, the shorter one padded with its fill value (Python's zip_longest).

zip_longest_opt fn

fn zip_longest_opt[A, B](xs: List[A], ys: List[B]) -> List[(Opt[A], Opt[B])]

Pairs as long as the longer list, with none where a list has run out.

unzip fn

fn unzip[A, B](ps: List[(A, B)]) -> (List[A], List[B])

The firsts and the seconds of a list of pairs.

unzip3 fn

fn unzip3[A, B, C](ts: List[(A, B, C)]) -> (List[A], List[B], List[C])

The three components of a list of triples.

transpose fn

fn transpose[A](rows: List[List[A]]) -> List[List[A]]

Rows become columns. Ragged input is allowed: column i holds element i of every row that has one, in row order, so it is shorter than the row count when some rows are short, and there are as many columns as the longest row has elements. [] gives [].

pairwise fn

fn pairwise[A](xs: List[A]) -> List[(A, A)]

Adjacent pairs: [(x0, x1), (x1, x2), ...], empty for fewer than two elements.

combinatorics_limit fn

fn combinatorics_limit() -> Int

The most lists or pairs the combinatoric functions return: 1,000,000. Their pre clauses reject inputs whose output would be larger, so a typo can't ask for a trillion permutations.

cartesian fn

fn cartesian[A, B](xs: List[A], ys: List[B]) -> List[(A, B)]

Every pair (x, y) with x from xs and y from ys, x varying slowest. At most combinatorics_limit() pairs.

cartesian_all fn

fn cartesian_all[A](xss: List[List[A]]) -> List[List[A]]

The n-ary cartesian product (Python's itertools.product): every list taking one element from each list of xss, the last varying fastest. [] gives [[]], and any empty list gives []. At most combinatorics_limit() lists.

permutations fn

fn permutations[A](xs: List[A], k: Int where _ >= 0) -> List[List[A]]

The k-permutations of xs by position, in lexicographic order of positions (Python's itertools.permutations(xs, k)): n! / (n - k)! lists, [[]] for k == 0 and [] for k > xs.len. Equal elements are treated as distinct. At most combinatorics_limit() lists.

combinations fn

fn combinations[A](xs: List[A], k: Int where _ >= 0) -> List[List[A]]

The k-combinations of xs by position, in lexicographic order of positions, each in input order (Python's itertools.combinations): C(n, k) lists, [[]] for k == 0 and [] for k > xs.len. At most combinatorics_limit() lists.

combinations_with_replacement fn

fn combinations_with_replacement[A](xs: List[A], k: Int where _ >= 0) -> List[List[A]]

The k-combinations with repetition (Python's combinations_with_replacement): C(n + k - 1, k) lists in lexicographic order of positions; [[]] for k == 0, [] for an empty xs and k > 0. At most combinatorics_limit() lists.

power_set fn

fn power_set[A](xs: List[A]) -> List[List[A]]

Every sublist of xs (keeping input order), by size and then lexicographically by position: 2 ** xs.len lists, starting with []. At most 20 elements (1,048,576 lists).

count_permutations fn

fn count_permutations(n: Int, k: Int) -> Opt[Int]

The number of k-permutations of n items, n! / (n - k)! (0 when k > n), or none when it doesn't fit in an Int or an argument is negative.

count_combinations fn

fn count_combinations(n: Int, k: Int) -> Opt[Int]

The number of k-combinations of n items, the binomial coefficient (0 when k > n), or none when it doesn't fit in an Int or an argument is negative.

replicate fn

fn replicate[A](x: A, n: Int) -> List[A]

A list of n copies of x ([] when n <= 0).

cycle fn

fn cycle[A](xs: List[A], n: Int) -> List[A]

xs repeated n times ([] when n <= 0).

cycle_take fn

fn cycle_take[A](xs: List[A], n: Int) -> List[A]

The first n elements of xs repeated forever ([] when xs is empty or n <= 0).

map_indexed fn

fn map_indexed[A, B, e](xs: List[A], f: (Int, A) -> B ! e) -> List[B] ! e

f(i, x) for each element and its index.

filter_indexed fn

fn filter_indexed[A, e](xs: List[A], p: (Int, A) -> Bool ! e) -> List[A] ! e

The elements for which p(i, x) holds, with i the index.

filter_map fn

fn filter_map[A, B, e](xs: List[A], f: A -> Opt[B] ! e) -> List[B] ! e

The values of f that are some, in order (Rust's filter_map).

compact fn

fn compact[A](xs: List[Opt[A]]) -> List[A]

The values inside the somes, in order.

find_map fn

fn find_map[A, B, e](xs: List[A], f: A -> Opt[B] ! e) -> Opt[B] ! e

The first some that f gives, calling f only until then (Rust's find_map).

partition_map fn

fn partition_map[A, B, C, e](xs: List[A], f: A -> Res[B, C] ! e) -> (List[B], List[C]) ! e

The ok values and the err values of f, each in order.

partition_results fn

fn partition_results[B, C](rs: List[Res[B, C]]) -> (List[B], List[C])

The ok values and the err values, each in order.

sequence_opt fn

fn sequence_opt[A](xs: List[Opt[A]]) -> Opt[List[A]]

some of every value when all are some, else none.

sequence_res fn

fn sequence_res[A, E](rs: List[Res[A, E]]) -> Res[List[A], E]

ok of every value when all are ok, else the first err.

at fn

fn at[A](xs: List[A], i: Int) -> Opt[A]

The element at i, counting from the end when i is negative (-1 is the last), or none when out of range.

insert_at fn

fn insert_at[A](xs: List[A], i: Int, x: A) -> List[A]

xs with x inserted before index i; i is clamped to 0..=xs.len, so a negative i inserts at the front and one past the end appends.

insert_all_at fn

fn insert_all_at[A](xs: List[A], i: Int, ys: List[A]) -> List[A]

xs with all of ys inserted before index i, clamped like insert_at.

remove_at fn

fn remove_at[A](xs: List[A], i: Int) -> List[A]

xs without the element at i; an out-of-range i (negative included) leaves it unchanged.

remove_first fn

fn remove_first[A](xs: List[A], x: A) -> List[A]

xs without the first element equal to x (unchanged when there is none). The builtin filter removes them all.

set_at fn

fn set_at[A](xs: List[A], i: Int, x: A) -> List[A]

xs with the element at i replaced by x; out of range leaves it unchanged.

update_at fn

fn update_at[A, e](xs: List[A], i: Int, f: A -> A ! e) -> List[A] ! e

xs with the element at i replaced by f of it; out of range leaves it unchanged and doesn't call f.

swap fn

fn swap[A](xs: List[A], i: Int, j: Int) -> List[A]

xs with the elements at i and j exchanged; unchanged when either is out of range.

move_item fn

fn move_item[A](xs: List[A], from: Int, to: Int) -> List[A]

xs with the element at from moved so that it ends at index to (clamped to the valid range); unchanged when from is out of range.

find_last fn

fn find_last[A, e](xs: List[A], p: A -> Bool ! e) -> Opt[A] ! e

The last element satisfying p, testing from the end.

find_last_index fn

fn find_last_index[A, e](xs: List[A], p: A -> Bool ! e) -> Opt[Int] ! e

The index of the last element satisfying p, testing from the end.

last_index_of fn

fn last_index_of[A](xs: List[A], x: A) -> Opt[Int]

The index of the last element equal to x.

indices_where fn

fn indices_where[A, e](xs: List[A], p: A -> Bool ! e) -> List[Int] ! e

The indexes of every element satisfying p, ascending.

indices_of fn

fn indices_of[A](xs: List[A], x: A) -> List[Int]

The indexes of every element equal to x, ascending.

partition_point fn

fn partition_point[A, e](xs: List[A], p: A -> Bool ! e) -> Int ! e

The first index at which p is false, for a list that is partitioned (every element satisfying p comes before every one that doesn't); xs.len when p holds everywhere. Binary search: p is called O(log n) times.

lower_bound_by fn

fn lower_bound_by[A, K: Ord, e](xs: List[A], key: A -> K ! e, target: K) -> Int ! e

The first index whose key is at least target, in a list sorted by key (xs.len if none).

upper_bound_by fn

fn upper_bound_by[A, K: Ord, e](xs: List[A], key: A -> K ! e, target: K) -> Int ! e

The first index whose key is greater than target, in a list sorted by key (xs.len if none).

binary_search_by fn

fn binary_search_by[A, K: Ord, e](xs: List[A], key: A -> K ! e, target: K) -> Opt[Int] ! e

The first index whose key equals target in a list sorted by key, or none.

insert_sorted fn

fn insert_sorted[T: Ord](xs: List[T], x: T) -> List[T]

x inserted into the sorted list xs after any equal elements, so the list stays sorted and insertion is stable.

insert_sorted_by fn

fn insert_sorted_by[A, K: Ord, e](xs: List[A], x: A, key: A -> K ! e) -> List[A] ! e

x inserted into xs, sorted by key, after any elements with an equal key.

index_of_sublist fn

fn index_of_sublist[A](xs: List[A], sub: List[A]) -> Opt[Int]

The first index at which sub occurs in xs as a contiguous run; some(0) for an empty sub. Worst case O(xs.len * sub.len).

last_index_of_sublist fn

fn last_index_of_sublist[A](xs: List[A], sub: List[A]) -> Opt[Int]

The last index at which sub occurs in xs; some(xs.len) for an empty sub.

contains_sublist fn

fn contains_sublist[A](xs: List[A], sub: List[A]) -> Bool

Whether sub occurs in xs as a contiguous run (always for an empty sub).

has_prefix fn

fn has_prefix[A](xs: List[A], prefix: List[A]) -> Bool

Whether xs starts with prefix.

has_suffix fn

fn has_suffix[A](xs: List[A], suffix: List[A]) -> Bool

Whether xs ends with suffix.

count_sublist fn

fn count_sublist[A](xs: List[A], sub: List[A]) -> Int

How many times sub occurs in xs without overlapping, scanning left to right (like Str.count in Python). An empty sub counts xs.len + 1 times.

replace_sublist fn

fn replace_sublist[A](xs: List[A], sub: List[A], by: List[A]) -> List[A]

xs with every non-overlapping occurrence of sub (left to right) replaced by by. An empty sub leaves xs unchanged.

fold_right fn

fn fold_right[A, B, e](xs: List[A], init: B, f: (A, B) -> B ! e) -> B ! e

Folds from the right: f(x0, f(x1, ... f(xn, init))).

reduce fn

fn reduce[A, e](xs: List[A], f: (A, A) -> A ! e) -> Opt[A] ! e

Folds from the left with the first element as the start, or none for an empty list.

reduce_right fn

fn reduce_right[A, e](xs: List[A], f: (A, A) -> A ! e) -> Opt[A] ! e

Folds from the right with the last element as the start, or none for an empty list.

scan_right fn

fn scan_right[A, B, e](xs: List[A], init: B, f: (A, B) -> B ! e) -> List[B] ! e

The accumulators of fold_right, aligned with the elements: element i of the result is f(xs[i], result[i + 1]), the last one f(xs[n - 1], init). Same length as xs, like the builtin scan.

is_sorted fn

fn is_sorted[T: Ord](xs: List[T]) -> Bool

Whether every element is at most the next one.

is_strictly_sorted fn

fn is_strictly_sorted[T: Ord](xs: List[T]) -> Bool

Whether every element is less than the next one (sorted, no repeats).

is_sorted_by fn

fn is_sorted_by[A, K: Ord, e](xs: List[A], key: A -> K ! e) -> Bool ! e

Whether the keys never decrease. key is called once per element.

is_sorted_with fn

fn is_sorted_with[A, e](xs: List[A], cmp: (A, A) -> Int ! e) -> Bool ! e

Whether cmp(a, b) <= 0 for every pair of neighbours, with a comparator like sort_with's.

argsort fn

fn argsort[T: Ord](xs: List[T]) -> List[Int]

The indexes that sort xs (stable: equal elements keep input order), NumPy's argsort. argsort(xs).map(i => xs[i]) is xs sorted.

argsort_by fn

fn argsort_by[A, K: Ord, e](xs: List[A], key: A -> K ! e) -> List[Int] ! e

The indexes that sort xs by key, stable. key is called once per element.

ranks fn

fn ranks[T: Ord](xs: List[T]) -> List[Int]

The 0-based position of each element in the stable sort (ordinal ranks: ties get consecutive ranks in input order). The inverse permutation of argsort.

dense_ranks fn

fn dense_ranks[T: Ord](xs: List[T]) -> List[Int]

Dense ranks: 0 for the smallest value, and one more for each larger distinct value; equal elements share a rank.

compare_lists fn

fn compare_lists[T: Ord](xs: List[T], ys: List[T]) -> Int

Lexicographic comparison by the elements' Ord: -1, 0 or 1. A proper prefix comes first.

merge_by fn

fn merge_by[A, K: Ord, e](xs: List[A], ys: List[A], key: A -> K ! e) -> List[A] ! e

The elements of the sorted lists xs and ys in one sorted list, by key; on equal keys elements of xs come first. The builtin merge does this for the elements themselves.

merge_all fn

fn merge_all[T: Ord](xss: List[List[T]]) -> List[T]

A k-way merge: every element of the lists in one sorted list, stable (on equals, earlier lists first). With sorted inputs this is the merge; any input gives a sorted result.

union fn

fn union[A](xs: List[A], ys: List[A]) -> List[A]

The distinct elements of xs and then of ys that are not in xs, each once, in first-seen order.

intersect fn

fn intersect[A](xs: List[A], ys: List[A]) -> List[A]

The distinct elements of xs that also occur in ys, in xs order.

difference fn

fn difference[A](xs: List[A], ys: List[A]) -> List[A]

The distinct elements of xs that don't occur in ys, in xs order.

sym_difference fn

fn sym_difference[A](xs: List[A], ys: List[A]) -> List[A]

The distinct elements in exactly one of the lists: those of xs first, then those of ys.

contains_all fn

fn contains_all[A](xs: List[A], ys: List[A]) -> Bool

Whether every element of ys occurs in xs (true for an empty ys).

contains_any fn

fn contains_any[A](xs: List[A], ys: List[A]) -> Bool

Whether some element of ys occurs in xs (false for an empty ys).

is_disjoint fn

fn is_disjoint[A](xs: List[A], ys: List[A]) -> Bool

Whether the lists have no element in common.

multi_intersect fn

fn multi_intersect[A](xs: List[A], ys: List[A]) -> List[A]

The multiset intersection, keeping duplicates: each value as many times as it occurs in both lists (the smaller count), in xs order.

multi_difference fn

fn multi_difference[A](xs: List[A], ys: List[A]) -> List[A]

The multiset difference: xs with one occurrence removed for each occurrence in ys, the earliest first (Python's Counter subtraction, keeping order).

multi_union fn

fn multi_union[A](xs: List[A], ys: List[A]) -> List[A]

The multiset union: all of xs, then the occurrences in ys beyond those in xs (each value as many times as the larger count).

is_permutation fn

fn is_permutation[A](xs: List[A], ys: List[A]) -> Bool

Whether ys is a permutation of xs: the same elements with the same counts.

sample fn

fn sample[A](xs: List[A], k: Int, seed: Int) -> List[A]

k distinct positions of xs chosen uniformly at random, in random order (Python's random.sample), as a pure function of seed like the builtin shuffle. k is clamped to 0..=xs.len.

sample_ordered fn

fn sample_ordered[A](xs: List[A], k: Int, seed: Int) -> List[A]

sample, with the chosen elements in their input order.

Versions

VersionPublishedCommitSourceEffects
0.1.0 2026-10-16357044583csnapshot