///|
/// Evaluate UniqueBy
fn eval_unique_by(
expr : Expr,
input : Json,
env : Env,
) -> Iter[Json] raise InterpreterError {
guard input is Array(arr) else {
raise TypeMismatch("array", @ast_internal.json_type_name(input))
}
let seen : Map[String, Bool] = Map([])
let results : Array[Json] = []
for elem in arr {
match eval_with_env(expr, elem, env).collect() {
[first, ..] => {
let key = @debug.to_string(first)
if !seen.contains(key) {
seen[key] = true
results.push(elem)
}
}
[] => ()
}
}
Iter::singleton(Json::array(results))
}
///|
/// Evaluate MinBy
fn eval_min_by(
expr : Expr,
input : Json,
env : Env,
) -> Iter[Json] raise InterpreterError {
guard input is Array(arr) else {
raise TypeMismatch("array", @ast_internal.json_type_name(input))
}
Iter::singleton(pick_min_by(expr, env, arr).unwrap_or(null))
}
///|
/// Evaluate MaxBy
fn eval_max_by(
expr : Expr,
input : Json,
env : Env,
) -> Iter[Json] raise InterpreterError {
guard input is Array(arr) else {
raise TypeMismatch("array", @ast_internal.json_type_name(input))
}
Iter::singleton(pick_max_by(expr, env, arr).unwrap_or(null))
}
///|
fn pick_min_by(
expr : Expr,
env : Env,
arr : ArrayView[Json],
) -> Json? raise InterpreterError {
match arr {
[] => None
[head, .. tail] =>
match eval_with_env(expr, head, env).collect() {
[] => None
[head_val, ..] => {
let (min_elem, _min_val) = reduce_min_by(
expr, env, head, head_val, tail,
)
Some(min_elem)
}
}
}
}
///|
fn reduce_min_by(
expr : Expr,
env : Env,
current_elem : Json,
current_val : Json,
rest : ArrayView[Json],
) -> (Json, Json) raise InterpreterError {
let mut min_elem = current_elem
let mut min_val = current_val
for elem in rest {
match eval_with_env(expr, elem, env).collect() {
[] => ()
[val, ..] =>
if compare_json(val, min_val) < 0 {
min_elem = elem
min_val = val
}
}
}
(min_elem, min_val)
}
///|
fn pick_max_by(
expr : Expr,
env : Env,
arr : ArrayView[Json],
) -> Json? raise InterpreterError {
match arr {
[] => None
[head, .. tail] =>
match eval_with_env(expr, head, env).collect() {
[] => None
[head_val, ..] => {
let (max_elem, _max_val) = reduce_max_by(
expr, env, head, head_val, tail,
)
Some(max_elem)
}
}
}
}
///|
fn reduce_max_by(
expr : Expr,
env : Env,
current_elem : Json,
current_val : Json,
rest : ArrayView[Json],
) -> (Json, Json) raise InterpreterError {
let mut max_elem = current_elem
let mut max_val = current_val
for elem in rest {
match eval_with_env(expr, elem, env).collect() {
[] => ()
[val, ..] =>
if compare_json(val, max_val) > 0 {
max_elem = elem
max_val = val
}
}
}
(max_elem, max_val)
}