std.sort
std.sort holds the array algorithms — ordering, transforming, and querying.
For sequence generation and slicing (range, chunk, take/drop, set ops)
see std.seq.
Many std.sort functions are also available as pipes on arrays directly —
sorter versions that mutate the receiver, e.g. arr:sort(), arr:map(fn),
arr:filter(fn) (see Pipes). The forms below
call them as pure functions (std.sort.sort(arr)), which return a new array.
Reference
sort(array[, comparator]) # ascending; comparator(a, b) returns true if a < b
sort_by(array, key) # sort objects by a string key
reverse(array)
shuffle(array)
unique(array) # remove duplicates, preserve order
flatten(array) # flatten nested arrays
slice(array, start[, end]) # end is exclusive
concat(array...) # join any number of arrays
fill(array, value[, start[, end]])
zip(array...)
every(array, predicate) # all elements pass?
some(array, predicate) # any element passes?
map(array, fn)
filter(array, predicate)
reduce(array, fn[, init])
find(array, predicate) # first matching VALUE, or nil
find_index(array, predicate)# first matching INDEX, or -1
find_all(collection, value) # all indices (array) or keys (object) matching
# NOTE: a VALUE to match, not a predicate like find/filter
Predicates are functions fn(element) { ... }; the sort comparator is
fn(a, b) { ... }.
Ordering
std.sort.sort([3, 1, 2]) # [1, 2, 3] (ascending)
std.sort.sort([3, 1, 2], fn(a, b) { return a > b }) # [3, 2, 1] descending
std.sort.reverse([1, 2, 3]) # [3, 2, 1]
A comparator that does not define a strict weak ordering (e.g. one that
always returns true) throws INVALID_ARGUMENT: “sort comparator does not
define a strict weak ordering”.
sort_by orders an array of objects by one of their string keys — great for
sorting records:
var people = [
{name: "Bob", age: 40},
{name: "Ann", age: 30},
{name: "Cal", age: 35}
]
var byName = std.sort.sort_by(people, "name")
print(byName[0].name, byName[1].name, byName[2].name) # Ann Bob Cal
var byAge = std.sort.sort_by(people, "age")
print(byAge[0].age, byAge[1].age, byAge[2].age) # 30 35 40
The same operations run as pipes on the receiver:
var arr = [3, 1, 2]
arr:sort() # arr is now [1, 2, 3]
print(arr)
Deduplicate and reshape
std.sort.unique([3, 1, 3, 2, 1, 3]) # [3, 1, 2] (first-occurrence order)
std.sort.flatten([1, [2, 3], [4, [5, 6]]]) # [1, 2, 3, 4, 5, 6] (recursive)
std.sort.concat([1, 2], [3, 4], [5]) # [1, 2, 3, 4, 5]
std.sort.slice([0, 1, 2, 3, 4], 1, 3) # [1, 2] (end exclusive)
std.sort.fill([0, 0, 0], 7, 1, 2) # [0, 7, 0] (range: 1..<2)
std.sort.zip([1, 2, 3], ["a", "b", "c"])
# [[1, "a"], [2, "b"], [3, "c"]]
unique matches duplicates by type name and string form, so 1, 1.0, and
"1" are three distinct elements.
zip pairs up elements positionally and is handy for building records from
parallel arrays:
var names = ["Ann", "Bob"]
var scores = [88, 92]
var rows = std.sort.map(std.sort.zip(names, scores),
fn(p) { return {name: p[0], score: p[1]} })
print(rows[0]) # {"name": "Ann", "score": 88}
Transforming with map / filter / reduce
map applies a function to every element. filter keeps only the elements for
which the predicate is truthy:
var nums = [1, 2, 3]
std.sort.map(nums, fn(x) { return x * x }) # [1, 4, 9]
std.sort.filter(nums, fn(x) { return x % 2 == 0 }) # [2]
# pipe form
var evens = [1, 2, 3, 4]
var onlyEven = evens:filter(fn(x) { return x % 2 == 0 })
print(onlyEven) # [2, 4]
reduce folds the array into a single value. With no init, the first
element is the starting accumulator and the fold runs from the second; with
init, it starts from that value:
std.sort.reduce([1, 2, 3, 4], fn(a, b) { return a + b }) # 10
std.sort.reduce([1, 2, 3], fn(a, b) { return a + b }, 100) # 106
# longest-string idiom
var words = ["a", "bbb", "cc"]
var longest = std.sort.reduce(words, fn(best, w) {
return (len(w) > len(best)) ? w : best
})
print(longest) # bbb
Querying
every is true only if all elements pass; some if at least one passes. The
find family locates matches:
var nums = [1, 2, 3, 4]
std.sort.every(nums, fn(x) { return x > 0 }) # true
std.sort.some(nums, fn(x) { return x % 2 == 0 }) # true
std.sort.find(nums, fn(x) { return x > 2 }) # 3 (the VALUE)
std.sort.find_index(nums, fn(x) { return x > 2 }) # 2 (the INDEX)
std.sort.find_all([1, 2, 2, 3, 2], 2) # [1, 2, 4]
find returns the first matching value (nil if none) and is a compact “first
object where …” lookup:
var orders = [{id: 1, paid: false}, {id: 2, paid: true}]
var paid = std.sort.find(orders, fn(o) { return o.paid })
print(paid.id) # 2
See also
- std.seq —
range,chunk,take/drop,enumerate, set operations