LEVIATHAN v962456e · 962456eee1

Standard Library

class OrderedArray<T>

An array that has been sorted by one or more keys, produced by Array.orderBy and thenBy.

since 0.1.0-alpha.1linuxwindowswasm

bases
IIterable<T>

Overview

Sorting by several keys is written as a chain: orderBy sorts by the first key, and each thenBy sorts by one more key, but only among elements that are still tied on every earlier key, so a later key can never reorder elements that an earlier key already separated. The sort is stable, so elements tied on every key keep their original relative order.

An OrderedArray is a read-only result. Call toArray to get a plain Array<T>, or iterate it directly with for. It is not created with new; start from orderBy.

Description

orderBy and thenBy sort by several keys in sequence, the way a spreadsheet sorts by one column and then another. array.orderBy(key) sorts an Array<T> by key, a function from an element to a value that supports <, and returns an OrderedArray<T>. Calling .thenBy(key2) on that result sorts again by key2, but only inside groups of elements that were still tied on every earlier key. Any number of thenBy calls can be chained:

people.orderBy((p) => p.last).thenBy((p) => p.first)

Each sort is stable: elements that tie on every key keep their order from the source array. A call to orderBy on its own is the one-key case of the same algorithm.

thenBy exists only on OrderedArray, not on Array. That is deliberate: there is no way to write a tie-break on an array that has not been sorted yet. To leave the wrapper, call toArray(), which returns a plain Array<T>, or iterate the OrderedArray directly with for, since it is iterable. length() and isEmpty() work as on an array.

Sorting never changes the source array; orderBy and thenBy follow the same value rule as the rest of the library and return new results. You do not construct an OrderedArray yourself: orderBy and thenBy produce it.

Sort by last name, then first name

struct Person { string last; string first; int age; }
Array<Person> people = [Person("Smith", "Zed", 40), Person("Jones", "Amy", 30), Person("Smith", "Abe", 25), Person("Jones", "Bob", 30)];
OrderedArray<Person> byName = people.orderBy((p) => p.last).thenBy((p) => p.first);
for (Person p in byName) { console.writeln("${p.last} ${p.first}"); }
console.writeln(byName.length());
Array<Person> plain = byName.toArray();
console.writeln(plain[0].first);
for (Person p in people.orderBy((p) => p.age)) { console.writeln("${p.age} ${p.first}"); }
console.writeln(people[0].first);
Jones Amy
Jones Bob
Smith Abe
Smith Zed
4
Amy
25 Abe
30 Amy
30 Bob
40 Zed
Zed

Rules

  • thenBy breaks ties only within runs of elements equal on all earlier keys; it never reorders elements that an earlier key already separated.
  • Keys are compared with <. A key type without < is an error when the sort is instantiated.
  • The sort is stable, so elements equal on every key keep their source order (Amy before Bob in the example above, which are tied on age).
  • The source Array is not modified.

Examples

Ties keep source order

Array<string> words = ["pear", "fig", "apple", "kiwi", "plum"];
for (string w in words.orderBy((s) => s.length())) { console.writeln(w); }
console.writeln("--");
for (string w in words.orderBy((s) => s.length()).thenBy((s) => s)) { console.writeln(w); }
fig
pear
kiwi
plum
apple
--
fig
kiwi
pear
plum
apple

Examples

Sorting by age, then by name

Array<Pair<string, int>> people = [
    Pair::Of("bob", 30), Pair::Of("amy", 25), Pair::Of("cy", 30), Pair::Of("al", 25)
];
OrderedArray<Pair<string, int>> sorted = people.orderBy((p) => p.second).thenBy((p) => p.first);
for (Pair<string, int> p in sorted) {
    console.writeln("${p.second} ${p.first}");
}
console.writeln(sorted.length());
25 al
25 amy
30 bob
30 cy
4

Methods

isEmpty

isEmpty() -> bool

Whether there are no elements.

Returns

true when the ordered array is empty.

Examples

Emptiness

Array<int> e = [];
console.writeln(e.orderBy((x) => x).isEmpty());
console.writeln([1].orderBy((x) => x).isEmpty());
true
false

iterator

iterator() -> IIterator<T>

Return an iterator over the elements in sorted order.

A for loop over an OrderedArray uses this, so you rarely call it yourself.

Returns

An iterator positioned before the first element.

Examples

Iterating directly

Array<string> w = ["pear", "fig", "plum"];
for (string s in w.orderBy((x) => x.length())) {
    console.writeln(s);
}
fig
pear
plum

length

length() -> int

The number of elements.

Returns

The element count, the same as the array that was sorted.

Examples

Counting

Array<int> a = [5, 3, 4];
console.writeln(a.orderBy((x) => x).length());
3

thenBy

thenBy<K>((T) => K key) -> OrderedArray<T>

Refine the ordering by one more key, applied only to elements tied on every earlier key.

Elements that an earlier key (the orderBy key or an earlier thenBy key) already placed in different positions are never reordered. The key type K must support <. The sort is stable, so elements still tied afterwards keep their original relative order. The receiver is not changed.

Parameters

key
Computes the next sort key of an element.

Returns

A new OrderedArray; chain further thenBy calls on it for more keys.

Examples

Length first, then alphabetical

Array<string> w = ["bb", "a", "cc", "b", "aa", "c"];
Array<string> r = w.orderBy((s) => s.length()).thenBy((s) => s).toArray();
console.writeln(r);
Array<Pair<int, int>> ps = [Pair::Of(1, 2), Pair::Of(1, 1), Pair::Of(0, 5), Pair::Of(1, 1)];
OrderedArray<Pair<int, int>> o = ps.orderBy((p) => p.first).thenBy((p) => p.second);
for (Pair<int, int> p in o) {
    console.writeln("${p.first} ${p.second}");
}
[a, b, c, aa, bb, cc]
0 5
1 1
1 1
1 2

See also: orderBy

toArray

toArray() -> Array<T>

The sorted elements as a plain array.

Returns

An Array<T> in the sorted order.

Examples

Back to an array

Array<int> a = [5, 3, 4];
Array<int> sorted = a.orderBy((x) => x).toArray();
console.writeln(sorted);
console.writeln(a);
[3, 4, 5]
[5, 3, 4]

See also

  • orderBy — Start a multi-key sort: order by key, and let thenBy break ties.
  • Array — An ordered sequence of values of one type, Array<T>, with value semantics.