5.1.28. LINQ — Language-Integrated Query
This tutorial covers daslang’s LINQ module for C#-style query operations on
iterators and arrays, plus the linq_boost macros for composing pipelines.
5.1.28.1. Setup
Import both modules:
require daslib/linq
require daslib/linq_boost
Most LINQ functions come in several flavors:
func(iterator, ...)— returns a lazy iteratorfunc(array, ...)— returns a new arrayfunc_to_array(iterator, ...)— materializes into an arrayfunc_inplace(var array, ...)— mutates in place
5.1.28.2. Filtering
where_ filters elements by a predicate (the trailing underscore avoids
collision with the built-in keyword):
var numbers = [3, 1, 4, 1, 5, 9, 2, 6, 5]
var evens = where_to_array(numbers.to_sequence(), $(x) => x % 2 == 0)
// evens: [4, 2, 6]
The _where shorthand uses _ as the element placeholder:
var big = _where_to_array(numbers.to_sequence(), _ > 4)
// big: [5, 9, 6, 5]
5.1.28.3. Projection
select transforms each element:
var doubled = _select_to_array(numbers.to_sequence(), _ * 2)
// doubled: [6, 2, 8, 2, 10, 18, 4, 12, 10]
select_many flattens nested sequences into one:
var nested = [
["a", "b", "c"].to_sequence(),
["d", "e", "f"].to_sequence()
]
var flat = select_many_to_array(
nested.to_sequence(),
$(s : string) => "{s}!"
)
// flat: ["a!", "b!", "c!", "d!", "e!", "f!"]
5.1.28.4. Sorting
order sorts ascending, order_descending sorts descending:
var unsorted = [5, 3, 8, 1, 4]
var asc = order(unsorted) // [1, 3, 4, 5, 8]
var desc = order_descending(unsorted) // [8, 5, 4, 3, 1]
Sort structs by a field with _order_by:
var by_age = _order_by(team.to_sequence(), _.age)
5.1.28.5. Partitioning
skip(arr, n)/take(arr, n)— from the frontskip_last(arr, n)/take_last(arr, n)— from the endskip_while/take_while— by predicatechunk(iter, n)— split into groups of N
var seq = [for (x in 0..8); x]
skip(seq, 3) // [3, 4, 5, 6, 7]
take(seq, 3) // [0, 1, 2]
take_last(seq, 3) // [5, 6, 7]
skip_last(seq, 3) // [0, 1, 2, 3, 4]
5.1.28.6. Aggregation
Function |
Description |
|---|---|
|
Number of elements |
|
Number of elements matching predicate |
|
Sum of elements |
|
Arithmetic mean |
|
Minimum / maximum |
|
Custom fold with seed |
var vals = [10, 20, 30, 40, 50]
count(vals) // 5
count(vals, $(v) => v > 25) // 3
sum(vals.to_sequence()) // 150
aggregate(vals.to_sequence(), 1, $(acc, v) => acc * v) // 12000000
The _count shorthand works like _where:
_count(vals.to_sequence(), _ >= 30) // 3
5.1.28.7. Element access
first/last— first or last element (panics if empty)first_or_default/last_or_default— returns default if emptyelement_at(iter, i)/element_at_or_default(iter, i)single— returns the only element (panics if count ≠ 1)
5.1.28.8. Querying
any(vals.to_sequence(), $(v) => v > 40) // true
all(vals.to_sequence(), $(v) => v > 5) // true
contains(vals.to_sequence(), 30) // true
5.1.28.9. Set operations
var a = [1, 2, 2, 3, 3, 3]
var b = [2, 3, 4, 5]
distinct(a) // [1, 2, 3]
union(a, b) // [1, 2, 3, 4, 5]
except(a, b) // [1]
intersect(a, b) // [2, 3]
5.1.28.10. Zip
zip merges two or three sequences into tuples:
var names = ["Alice", "Bob", "Charlie"]
var ages = [25, 35, 30]
var zipped = zip(names, ages)
// zipped: [(Alice,25), (Bob,35), (Charlie,30)]
var scores = [95, 87, 91]
var zipped3 = zip(names, ages, scores)
// zipped3: [(Alice,25,95), (Bob,35,87), (Charlie,30,91)]
5.1.28.11. The _fold pipeline macro
_fold composes multiple LINQ operations into an optimized pipeline
using dot-chaining:
// Sum of squares of even numbers
var result = (
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
._where(_ % 2 == 0)
._select(_ * _)
.sum()
._fold()
)
// result: 220
// Top 3 unique values, descending
var top3 = (
[5, 3, 8, 1, 4, 8, 3, 9, 2, 9]
.order_descending()
.distinct()
.take(3)
._fold()
)
// top3: [9, 8, 5]
The _fold macro rewrites the chain into efficient imperative code at
compile time, avoiding intermediate allocations.