use crate::step::{cont, Step};
use crate::transducer::Transducer;
use std::collections::{HashMap, HashSet};
use std::hash::Hash;
pub fn to_vec<T, U, Iter>(transducer: &impl Transducer<T, U>, source: Iter) -> Vec<U>
where
T: 'static,
U: 'static,
Iter: IntoIterator<Item = T>,
{
let reducer = |mut acc: Vec<U>, x: U| {
acc.push(x);
cont(acc)
};
let transformed = transducer.apply(reducer);
let mut result = Vec::new();
for item in source {
match transformed(result, item) {
Step::Continue(new_result) => result = new_result,
Step::Stop(final_result) => {
result = final_result;
break;
}
}
}
result
}
pub fn reduce<T, U, Acc, Iter, R>(
transducer: &impl Transducer<T, U>,
source: Iter,
initial: Acc,
reducer: R,
) -> Acc
where
T: 'static,
U: 'static,
Acc: 'static,
Iter: IntoIterator<Item = T>,
R: Fn(Acc, U) -> Step<Acc> + 'static,
{
let transformed = transducer.apply(reducer);
let mut acc = initial;
for item in source {
match transformed(acc, item) {
Step::Continue(new_acc) => acc = new_acc,
Step::Stop(final_acc) => {
acc = final_acc;
break;
}
}
}
acc
}
pub fn sum<T, U, Iter>(transducer: &impl Transducer<T, U>, source: Iter) -> U
where
T: 'static,
U: std::ops::Add<Output = U> + Default + 'static,
Iter: IntoIterator<Item = T>,
{
reduce(transducer, source, U::default(), |acc, x| cont(acc + x))
}
pub fn count<T, U, Iter>(transducer: &impl Transducer<T, U>, source: Iter) -> usize
where
T: 'static,
U: 'static,
Iter: IntoIterator<Item = T>,
{
reduce(transducer, source, 0usize, |acc, _| cont(acc + 1))
}
pub fn first<T, U, Iter>(transducer: &impl Transducer<T, U>, source: Iter) -> Option<U>
where
T: 'static,
U: 'static,
Iter: IntoIterator<Item = T>,
{
use crate::step::stop;
let reducer = |_acc: Option<U>, x: U| stop(Some(x));
reduce(transducer, source, None, reducer)
}
pub fn last<T, U, Iter>(transducer: &impl Transducer<T, U>, source: Iter) -> Option<U>
where
T: 'static,
U: 'static,
Iter: IntoIterator<Item = T>,
{
reduce(transducer, source, None, |_acc, x| cont(Some(x)))
}
pub fn every<T, U, Iter, P>(transducer: &impl Transducer<T, U>, source: Iter, predicate: P) -> bool
where
T: 'static,
U: 'static,
Iter: IntoIterator<Item = T>,
P: Fn(&U) -> bool + 'static,
{
use crate::step::stop;
let reducer = move |_acc: bool, x: U| {
if predicate(&x) {
cont(true)
} else {
stop(false)
}
};
reduce(transducer, source, true, reducer)
}
pub fn some<T, U, Iter, P>(transducer: &impl Transducer<T, U>, source: Iter, predicate: P) -> bool
where
T: 'static,
U: 'static,
Iter: IntoIterator<Item = T>,
P: Fn(&U) -> bool + 'static,
{
use crate::step::stop;
let reducer = move |_acc: bool, x: U| {
if predicate(&x) {
stop(true)
} else {
cont(false)
}
};
reduce(transducer, source, false, reducer)
}
pub fn partition<T, U, Iter, P>(
transducer: &impl Transducer<T, U>,
source: Iter,
predicate: P,
) -> (Vec<U>, Vec<U>)
where
T: 'static,
U: 'static,
Iter: IntoIterator<Item = T>,
P: Fn(&U) -> bool + 'static,
{
let reducer = move |mut acc: (Vec<U>, Vec<U>), x: U| {
if predicate(&x) {
acc.0.push(x);
} else {
acc.1.push(x);
}
cont(acc)
};
reduce(transducer, source, (Vec::new(), Vec::new()), reducer)
}
pub fn find<T, U, Iter, P>(
transducer: &impl Transducer<T, U>,
source: Iter,
predicate: P,
) -> Option<U>
where
T: 'static,
U: 'static,
Iter: IntoIterator<Item = T>,
P: Fn(&U) -> bool + 'static,
{
use crate::step::stop;
let reducer = move |_acc: Option<U>, x: U| {
if predicate(&x) {
stop(Some(x))
} else {
cont(None)
}
};
reduce(transducer, source, None, reducer)
}
pub fn group_by<T, U, K, Iter, F>(
transducer: &impl Transducer<T, U>,
source: Iter,
key_fn: F,
) -> HashMap<K, Vec<U>>
where
T: 'static,
U: 'static,
K: Eq + Hash + 'static,
Iter: IntoIterator<Item = T>,
F: Fn(&U) -> K + 'static,
{
let reducer = move |mut acc: HashMap<K, Vec<U>>, x: U| {
let key = key_fn(&x);
acc.entry(key).or_default().push(x);
cont(acc)
};
reduce(transducer, source, HashMap::new(), reducer)
}
pub fn none<T, U, Iter, P>(transducer: &impl Transducer<T, U>, source: Iter, predicate: P) -> bool
where
T: 'static,
U: 'static,
Iter: IntoIterator<Item = T>,
P: Fn(&U) -> bool + 'static,
{
use crate::step::stop;
let reducer = move |_acc: bool, x: U| {
if predicate(&x) {
stop(false) } else {
cont(true) }
};
reduce(transducer, source, true, reducer)
}
pub fn contains<T, U, Iter>(transducer: &impl Transducer<T, U>, source: Iter, value: &U) -> bool
where
T: 'static,
U: PartialEq + Clone + 'static,
Iter: IntoIterator<Item = T>,
{
use crate::step::stop;
let target = value.clone();
let reducer = move |_acc: bool, x: U| {
if x == target {
stop(true) } else {
cont(false) }
};
reduce(transducer, source, false, reducer)
}
pub fn zip<T, U, IterT, IterU>(iter_a: IterT, iter_b: IterU) -> Vec<(T, U)>
where
IterT: IntoIterator<Item = T>,
IterU: IntoIterator<Item = U>,
{
iter_a.into_iter().zip(iter_b).collect()
}
pub fn zip_with<T, U, V, IterT, IterU, F>(iter_a: IterT, iter_b: IterU, combine: F) -> Vec<V>
where
IterT: IntoIterator<Item = T>,
IterU: IntoIterator<Item = U>,
F: Fn(T, U) -> V,
{
iter_a
.into_iter()
.zip(iter_b)
.map(|(a, b)| combine(a, b))
.collect()
}
pub fn merge<T, I>(iterators: Vec<I>) -> Vec<T>
where
I: IntoIterator<Item = T>,
{
let mut iters: Vec<_> = iterators.into_iter().map(|i| i.into_iter()).collect();
let mut result = Vec::new();
let mut active = true;
while active {
active = false;
for iter in &mut iters {
if let Some(val) = iter.next() {
result.push(val);
active = true;
}
}
}
result
}
pub fn intersection<T, IterA, IterB>(iter_a: IterA, iter_b: IterB) -> Vec<T>
where
T: Eq + Hash + Clone,
IterA: IntoIterator<Item = T>,
IterB: IntoIterator<Item = T>,
{
let set_b: HashSet<T> = iter_b.into_iter().collect();
iter_a
.into_iter()
.filter(|item| set_b.contains(item))
.collect()
}
pub fn difference<T, IterA, IterB>(iter_a: IterA, iter_b: IterB) -> Vec<T>
where
T: Eq + Hash + Clone,
IterA: IntoIterator<Item = T>,
IterB: IntoIterator<Item = T>,
{
let set_b: HashSet<T> = iter_b.into_iter().collect();
iter_a
.into_iter()
.filter(|item| !set_b.contains(item))
.collect()
}
pub fn union<T, IterA, IterB>(iter_a: IterA, iter_b: IterB) -> Vec<T>
where
T: Eq + Hash + Clone,
IterA: IntoIterator<Item = T>,
IterB: IntoIterator<Item = T>,
{
let mut seen = HashSet::new();
let mut result = Vec::new();
for item in iter_a {
if seen.insert(item.clone()) {
result.push(item);
}
}
for item in iter_b {
if seen.insert(item.clone()) {
result.push(item);
}
}
result
}
pub fn symmetric_difference<T, IterA, IterB>(iter_a: IterA, iter_b: IterB) -> Vec<T>
where
T: Eq + Hash + Clone,
IterA: IntoIterator<Item = T>,
IterB: IntoIterator<Item = T>,
{
let vec_a: Vec<T> = iter_a.into_iter().collect();
let vec_b: Vec<T> = iter_b.into_iter().collect();
let set_a: HashSet<&T> = vec_a.iter().collect();
let set_b: HashSet<&T> = vec_b.iter().collect();
let mut result = Vec::new();
let mut seen = HashSet::new();
for item in &vec_a {
if !set_b.contains(item) && seen.insert(item) {
result.push(item.clone());
}
}
for item in &vec_b {
if !set_a.contains(item) && seen.insert(item) {
result.push(item.clone());
}
}
result
}
pub fn reservoir_sample<T, U, Iter>(
transducer: &impl Transducer<T, U>,
source: Iter,
n: usize,
) -> Vec<U>
where
T: 'static,
U: 'static + Clone,
Iter: IntoIterator<Item = T>,
{
use rand::Rng;
use std::cell::RefCell;
use std::rc::Rc;
let rng = Rc::new(RefCell::new(rand::thread_rng()));
let reservoir: Rc<RefCell<Vec<U>>> = Rc::new(RefCell::new(Vec::with_capacity(n)));
let count = Rc::new(RefCell::new(0usize));
let reducer = {
let rng = Rc::clone(&rng);
let reservoir = Rc::clone(&reservoir);
let count = Rc::clone(&count);
move |_acc: (), x: U| {
let mut c = count.borrow_mut();
*c += 1;
let mut res = reservoir.borrow_mut();
if res.len() < n {
res.push(x);
} else {
let mut rng_mut = rng.borrow_mut();
let j = rng_mut.gen_range(0..*c);
if j < n {
res[j] = x;
}
}
cont(())
}
};
reduce(transducer, source, (), reducer);
Rc::try_unwrap(reservoir)
.unwrap_or_else(|_| panic!("Failed to unwrap reservoir"))
.into_inner()
}
pub fn partition_by<T, U, K, Iter, F>(
transducer: &impl Transducer<T, U>,
source: Iter,
key_fn: F,
) -> Vec<Vec<U>>
where
T: 'static,
U: 'static + Clone,
K: Eq + Hash + 'static,
Iter: IntoIterator<Item = T>,
F: Fn(&U) -> K + 'static,
{
use std::cell::RefCell;
use std::rc::Rc;
let result: Rc<RefCell<Vec<Vec<U>>>> = Rc::new(RefCell::new(Vec::new()));
let current_group: Rc<RefCell<Vec<U>>> = Rc::new(RefCell::new(Vec::new()));
let current_key: Rc<RefCell<Option<K>>> = Rc::new(RefCell::new(None));
let reducer = {
let result = Rc::clone(&result);
let current_group = Rc::clone(¤t_group);
let current_key = Rc::clone(¤t_key);
move |_acc: (), x: U| {
let key = key_fn(&x);
let mut key_ref = current_key.borrow_mut();
let mut group_ref = current_group.borrow_mut();
match key_ref.as_ref() {
None => {
*key_ref = Some(key);
group_ref.push(x);
}
Some(prev_key) if key == *prev_key => {
group_ref.push(x);
}
Some(_) => {
if !group_ref.is_empty() {
result.borrow_mut().push(group_ref.clone());
group_ref.clear();
}
*key_ref = Some(key);
group_ref.push(x);
}
}
cont(())
}
};
reduce(transducer, source, (), reducer);
let final_group = current_group.borrow().clone();
if !final_group.is_empty() {
result.borrow_mut().push(final_group);
}
Rc::try_unwrap(result)
.unwrap_or_else(|_| panic!("Failed to unwrap result"))
.into_inner()
}
pub fn top_k<T, U, Iter>(transducer: &impl Transducer<T, U>, source: Iter, k: usize) -> Vec<U>
where
T: 'static,
U: Ord + Clone + 'static,
Iter: IntoIterator<Item = T>,
{
use std::cell::RefCell;
use std::cmp::Reverse;
use std::collections::BinaryHeap;
use std::rc::Rc;
let heap: Rc<RefCell<BinaryHeap<Reverse<U>>>> =
Rc::new(RefCell::new(BinaryHeap::with_capacity(k + 1)));
let reducer = {
let heap = Rc::clone(&heap);
move |_acc: (), x: U| {
let mut heap_ref = heap.borrow_mut();
if heap_ref.len() < k {
heap_ref.push(Reverse(x));
} else if let Some(Reverse(min)) = heap_ref.peek() {
if &x > min {
heap_ref.push(Reverse(x));
if heap_ref.len() > k {
heap_ref.pop();
}
}
}
cont(())
}
};
reduce(transducer, source, (), reducer);
let final_heap = Rc::try_unwrap(heap)
.unwrap_or_else(|_| panic!("Failed to unwrap heap"))
.into_inner();
let mut result: Vec<U> = final_heap.into_iter().map(|Reverse(x)| x).collect();
result.sort_by(|a, b| b.cmp(a)); result
}
pub fn frequencies<T, U, Iter>(
transducer: &impl Transducer<T, U>,
source: Iter,
) -> HashMap<U, usize>
where
T: 'static,
U: Eq + Hash + Clone + 'static,
Iter: IntoIterator<Item = T>,
{
let reducer = |mut acc: HashMap<U, usize>, x: U| {
*acc.entry(x).or_insert(0) += 1;
cont(acc)
};
reduce(transducer, source, HashMap::new(), reducer)
}
pub fn zip_longest<T, U, IterT, IterU>(
iter_a: IterT,
iter_b: IterU,
fill_a: T,
fill_b: U,
) -> Vec<(T, U)>
where
T: Clone,
U: Clone,
IterT: IntoIterator<Item = T>,
IterU: IntoIterator<Item = U>,
{
let mut iter_a = iter_a.into_iter();
let mut iter_b = iter_b.into_iter();
let mut result = Vec::new();
loop {
match (iter_a.next(), iter_b.next()) {
(Some(a), Some(b)) => result.push((a, b)),
(Some(a), None) => result.push((a, fill_b.clone())),
(None, Some(b)) => result.push((fill_a.clone(), b)),
(None, None) => break,
}
}
result
}
pub fn cartesian_product<T, U, IterT, IterU>(iter_a: IterT, iter_b: IterU) -> Vec<(T, U)>
where
T: Clone,
U: Clone,
IterT: IntoIterator<Item = T>,
IterU: IntoIterator<Item = U>,
{
let vec_a: Vec<T> = iter_a.into_iter().collect();
let vec_b: Vec<U> = iter_b.into_iter().collect();
let mut result = Vec::with_capacity(vec_a.len() * vec_b.len());
for a in &vec_a {
for b in &vec_b {
result.push((a.clone(), b.clone()));
}
}
result
}
pub fn take_last<T, U, Iter>(transducer: &impl Transducer<T, U>, source: Iter, n: usize) -> Vec<U>
where
T: 'static,
U: Clone + 'static,
Iter: IntoIterator<Item = T>,
{
let all_elements = to_vec(transducer, source);
if all_elements.len() <= n {
all_elements
} else {
all_elements[all_elements.len() - n..].to_vec()
}
}
pub fn drop_last<T, U, Iter>(transducer: &impl Transducer<T, U>, source: Iter, n: usize) -> Vec<U>
where
T: 'static,
U: Clone + 'static,
Iter: IntoIterator<Item = T>,
{
let all_elements = to_vec(transducer, source);
if n >= all_elements.len() {
Vec::new()
} else {
all_elements[..all_elements.len() - n].to_vec()
}
}
pub fn product<T, U, Iter>(transducer: &impl Transducer<T, U>, source: Iter) -> U
where
T: 'static,
U: std::ops::Mul<Output = U> + From<u8> + 'static,
Iter: IntoIterator<Item = T>,
{
reduce(transducer, source, U::from(1u8), |acc, x| cont(acc * x))
}
pub fn mean<T, U, Iter>(transducer: &impl Transducer<T, U>, source: Iter) -> Option<f64>
where
T: 'static,
U: Into<f64> + 'static,
Iter: IntoIterator<Item = T>,
{
let elements = to_vec(transducer, source);
if elements.is_empty() {
None
} else {
let len = elements.len();
let sum: f64 = elements.into_iter().map(|x| x.into()).sum();
Some(sum / (len as f64))
}
}
pub fn median<T, U, Iter>(transducer: &impl Transducer<T, U>, source: Iter) -> Option<f64>
where
T: 'static,
U: Into<f64> + PartialOrd + 'static,
Iter: IntoIterator<Item = T>,
{
let elements = to_vec(transducer, source);
if elements.is_empty() {
return None;
}
let mut values: Vec<f64> = elements.into_iter().map(|x| x.into()).collect();
values.sort_by(|a, b| a.partial_cmp(b).unwrap_or(std::cmp::Ordering::Equal));
let len = values.len();
if len % 2 == 1 {
Some(values[len / 2])
} else {
Some((values[len / 2 - 1] + values[len / 2]) / 2.0)
}
}
pub fn min<T, U, Iter>(transducer: &impl Transducer<T, U>, source: Iter) -> Option<U>
where
T: 'static,
U: Ord + 'static,
Iter: IntoIterator<Item = T>,
{
let elements = to_vec(transducer, source);
elements.into_iter().min()
}
pub fn max<T, U, Iter>(transducer: &impl Transducer<T, U>, source: Iter) -> Option<U>
where
T: 'static,
U: Ord + 'static,
Iter: IntoIterator<Item = T>,
{
let elements = to_vec(transducer, source);
elements.into_iter().max()
}
pub fn min_by<T, U, K, Iter, F>(
transducer: &impl Transducer<T, U>,
source: Iter,
key_fn: F,
) -> Option<U>
where
T: 'static,
U: 'static,
K: Ord,
Iter: IntoIterator<Item = T>,
F: Fn(&U) -> K,
{
let elements = to_vec(transducer, source);
elements.into_iter().min_by_key(key_fn)
}
pub fn max_by<T, U, K, Iter, F>(
transducer: &impl Transducer<T, U>,
source: Iter,
key_fn: F,
) -> Option<U>
where
T: 'static,
U: 'static,
K: Ord,
Iter: IntoIterator<Item = T>,
F: Fn(&U) -> K,
{
let elements = to_vec(transducer, source);
elements.into_iter().max_by_key(key_fn)
}
pub fn variance<T, U, Iter>(transducer: &impl Transducer<T, U>, source: Iter) -> Option<f64>
where
T: 'static,
U: Into<f64> + Clone + 'static,
Iter: IntoIterator<Item = T>,
{
let elements = to_vec(transducer, source);
if elements.len() < 2 {
return None;
}
let values: Vec<f64> = elements.into_iter().map(|x| x.into()).collect();
let n = values.len() as f64;
let mean_val = values.iter().sum::<f64>() / n;
let sum_squared_diff: f64 = values
.iter()
.map(|x| {
let diff = x - mean_val;
diff * diff
})
.sum();
Some(sum_squared_diff / (n - 1.0))
}
pub fn std_dev<T, U, Iter>(transducer: &impl Transducer<T, U>, source: Iter) -> Option<f64>
where
T: 'static,
U: Into<f64> + Clone + 'static,
Iter: IntoIterator<Item = T>,
{
variance(transducer, source).map(|v| v.sqrt())
}
pub fn quantile<T, U, Iter>(transducer: &impl Transducer<T, U>, source: Iter, p: f64) -> Option<f64>
where
T: 'static,
U: Into<f64> + PartialOrd + 'static,
Iter: IntoIterator<Item = T>,
{
if !(0.0..=1.0).contains(&p) {
return None;
}
let elements = to_vec(transducer, source);
if elements.is_empty() {
return None;
}
let mut values: Vec<f64> = elements.into_iter().map(|x| x.into()).collect();
values.sort_by(|a, b| a.partial_cmp(b).unwrap_or(std::cmp::Ordering::Equal));
let len = values.len();
if len == 1 {
return Some(values[0]);
}
let index = p * (len - 1) as f64;
let lower = index.floor() as usize;
let upper = index.ceil() as usize;
if lower == upper {
Some(values[lower])
} else {
let weight = index - lower as f64;
Some(values[lower] * (1.0 - weight) + values[upper] * weight)
}
}
pub fn mode<T, U, Iter>(transducer: &impl Transducer<T, U>, source: Iter) -> Option<U>
where
T: 'static,
U: Eq + Hash + Clone + 'static,
Iter: IntoIterator<Item = T>,
{
let elements = to_vec(transducer, source);
if elements.is_empty() {
return None;
}
let mut freq_map: HashMap<U, usize> = HashMap::new();
for elem in elements {
*freq_map.entry(elem).or_insert(0) += 1;
}
freq_map
.into_iter()
.max_by_key(|(_, count)| *count)
.map(|(value, _)| value)
}
pub fn sort_by<T, U, K, Iter, F>(
transducer: &impl Transducer<T, U>,
source: Iter,
key_fn: F,
) -> Vec<U>
where
T: 'static,
U: Clone + 'static,
K: Ord,
Iter: IntoIterator<Item = T>,
F: Fn(&U) -> K,
{
let mut elements = to_vec(transducer, source);
elements.sort_by_key(key_fn);
elements
}
pub fn sort_with<T, U, Iter, F>(
transducer: &impl Transducer<T, U>,
source: Iter,
comparator: F,
) -> Vec<U>
where
T: 'static,
U: Clone + 'static,
Iter: IntoIterator<Item = T>,
F: Fn(&U, &U) -> std::cmp::Ordering,
{
let mut elements = to_vec(transducer, source);
elements.sort_by(comparator);
elements
}
pub fn reverse<T, U, Iter>(transducer: &impl Transducer<T, U>, source: Iter) -> Vec<U>
where
T: 'static,
U: 'static,
Iter: IntoIterator<Item = T>,
{
let mut elements = to_vec(transducer, source);
elements.reverse();
elements
}
pub fn range(start: i32, end: i32, step: i32) -> Vec<i32> {
if step == 0 {
panic!("Step cannot be zero");
}
let mut result = Vec::new();
let mut current = start;
if step > 0 {
while current < end {
result.push(current);
current += step;
}
} else {
while current > end {
result.push(current);
current += step;
}
}
result
}
pub fn repeat<T: Clone>(value: T, n: usize) -> Vec<T> {
vec![value; n]
}
pub fn cycle<T: Clone>(vec: Vec<T>, n: usize) -> Vec<T> {
let mut result = Vec::with_capacity(vec.len() * n);
for _ in 0..n {
result.extend(vec.iter().cloned());
}
result
}
pub fn unfold<T, F>(seed: T, f: F, limit: usize) -> Vec<T>
where
T: Clone,
F: Fn(&T) -> Option<T>,
{
let mut result = Vec::new();
let mut current = seed;
let mut count = 0;
while count < limit {
match f(¤t) {
Some(next) => {
result.push(next.clone());
current = next;
count += 1;
}
None => break,
}
}
result
}
#[cfg(test)]
mod tests {
use super::*;
use crate::transforms::{Filter, Map};
#[test]
fn test_to_vec() {
let double = Map::new(|x: i32| x * 2);
let result = to_vec(&double, vec![1, 2, 3]);
assert_eq!(result, vec![2, 4, 6]);
}
#[test]
fn test_sum() {
let double = Map::new(|x: i32| x * 2);
let result = sum(&double, vec![1, 2, 3]);
assert_eq!(result, 12);
}
#[test]
fn test_count() {
let evens = Filter::new(|x: &i32| x % 2 == 0);
let result = count(&evens, vec![1, 2, 3, 4, 5]);
assert_eq!(result, 2);
}
#[test]
fn test_first() {
let evens = Filter::new(|x: &i32| x % 2 == 0);
let result = first(&evens, vec![1, 3, 4, 5]);
assert_eq!(result, Some(4));
}
#[test]
fn test_every() {
use crate::transducer::Identity;
let id = Identity::<i32>::new();
assert!(every(&id, vec![2, 4, 6], |x| x % 2 == 0));
assert!(!every(&id, vec![2, 3, 6], |x| x % 2 == 0));
}
#[test]
fn test_partition() {
use crate::transducer::Identity;
let id = Identity::<i32>::new();
let (evens, odds) = partition(&id, vec![1, 2, 3, 4, 5], |x| x % 2 == 0);
assert_eq!(evens, vec![2, 4]);
assert_eq!(odds, vec![1, 3, 5]);
}
#[test]
fn test_partition_with_transform() {
let double = Map::new(|x: i32| x * 2);
let (greater, lesser) = partition(&double, vec![1, 2, 3, 4, 5], |x| *x > 5);
assert_eq!(greater, vec![6, 8, 10]); assert_eq!(lesser, vec![2, 4]); }
#[test]
fn test_partition_all_pass() {
use crate::transducer::Identity;
let id = Identity::<i32>::new();
let (pass, fail) = partition(&id, vec![2, 4, 6], |x| x % 2 == 0);
assert_eq!(pass, vec![2, 4, 6]);
assert_eq!(fail, Vec::<i32>::new());
}
#[test]
fn test_partition_all_fail() {
use crate::transducer::Identity;
let id = Identity::<i32>::new();
let (pass, fail) = partition(&id, vec![1, 3, 5], |x| x % 2 == 0);
assert_eq!(pass, Vec::<i32>::new());
assert_eq!(fail, vec![1, 3, 5]);
}
#[test]
fn test_find() {
use crate::transducer::Identity;
let id = Identity::<i32>::new();
let result = find(&id, vec![1, 3, 4, 5], |x| x % 2 == 0);
assert_eq!(result, Some(4));
}
#[test]
fn test_find_with_transform() {
let double = Map::new(|x: i32| x * 2);
let result = find(&double, vec![1, 2, 3, 4, 5], |x| *x > 5);
assert_eq!(result, Some(6)); }
#[test]
fn test_find_not_found() {
use crate::transducer::Identity;
let id = Identity::<i32>::new();
let result = find(&id, vec![1, 3, 5, 7], |x| x % 2 == 0);
assert_eq!(result, None);
}
#[test]
fn test_find_empty() {
use crate::transducer::Identity;
let id = Identity::<i32>::new();
let result = find(&id, Vec::<i32>::new(), |x| x % 2 == 0);
assert_eq!(result, None);
}
#[test]
fn test_group_by() {
use crate::transducer::Identity;
let id = Identity::<i32>::new();
let groups = group_by(&id, vec![1, 2, 3, 4, 5, 6], |x| x % 3);
assert_eq!(groups.get(&0), Some(&vec![3, 6]));
assert_eq!(groups.get(&1), Some(&vec![1, 4]));
assert_eq!(groups.get(&2), Some(&vec![2, 5]));
}
#[test]
fn test_group_by_with_transform() {
let double = Map::new(|x: i32| x * 2);
let groups = group_by(&double, vec![1, 2, 3, 4, 5, 6], |x| x % 4);
assert_eq!(groups.get(&0), Some(&vec![4, 8, 12])); assert_eq!(groups.get(&2), Some(&vec![2, 6, 10])); }
#[test]
fn test_group_by_empty() {
use crate::transducer::Identity;
let id = Identity::<i32>::new();
let groups = group_by(&id, Vec::<i32>::new(), |x| x % 3);
assert!(groups.is_empty());
}
#[test]
fn test_group_by_single_group() {
use crate::transducer::Identity;
let id = Identity::<i32>::new();
let groups = group_by(&id, vec![3, 6, 9, 12], |x| x % 3);
assert_eq!(groups.get(&0), Some(&vec![3, 6, 9, 12]));
assert_eq!(groups.len(), 1);
}
#[test]
fn test_none() {
use crate::transducer::Identity;
let id = Identity::<i32>::new();
assert!(none(&id, vec![1, 3, 5, 7], |x| x % 2 == 0)); assert!(!none(&id, vec![1, 2, 3], |x| x % 2 == 0)); }
#[test]
fn test_none_empty() {
use crate::transducer::Identity;
let id = Identity::<i32>::new();
assert!(none(&id, vec![], |_x| true)); }
#[test]
fn test_none_with_transducer() {
use crate::transforms::Map;
let pipeline = Map::new(|x: i32| x * 2);
assert!(none(&pipeline, vec![1, 2, 3], |x| *x > 10));
assert!(!none(&pipeline, vec![1, 2, 6], |x| *x > 10)); }
#[test]
fn test_none_all_match() {
use crate::transducer::Identity;
let id = Identity::<i32>::new();
assert!(!none(&id, vec![2, 4, 6, 8], |x| x % 2 == 0));
}
#[test]
fn test_contains() {
use crate::transducer::Identity;
let id = Identity::<i32>::new();
assert!(contains(&id, vec![1, 2, 3, 4, 5], &3));
assert!(!contains(&id, vec![1, 2, 4, 5], &3));
}
#[test]
fn test_contains_empty() {
use crate::transducer::Identity;
let id = Identity::<i32>::new();
assert!(!contains(&id, vec![], &42));
}
#[test]
fn test_contains_first_element() {
use crate::transducer::Identity;
let id = Identity::<i32>::new();
assert!(contains(&id, vec![1, 2, 3], &1));
}
#[test]
fn test_contains_last_element() {
use crate::transducer::Identity;
let id = Identity::<i32>::new();
assert!(contains(&id, vec![1, 2, 3, 4, 5], &5));
}
#[test]
fn test_contains_with_transducer() {
use crate::transforms::Map;
let pipeline = Map::new(|x: i32| x * 2);
assert!(contains(&pipeline, vec![1, 2, 3], &4)); assert!(!contains(&pipeline, vec![1, 2, 3], &5)); }
#[test]
fn test_zip() {
let a = vec![1, 2, 3];
let b = vec!['a', 'b', 'c', 'd'];
let result = zip(a, b);
assert_eq!(result, vec![(1, 'a'), (2, 'b'), (3, 'c')]);
}
#[test]
fn test_zip_equal_length() {
let a = vec![1, 2, 3];
let b = vec![4, 5, 6];
let result = zip(a, b);
assert_eq!(result, vec![(1, 4), (2, 5), (3, 6)]);
}
#[test]
fn test_zip_with() {
let a = vec![1, 2, 3];
let b = vec![10, 20, 30];
let result = zip_with(a, b, |x, y| x + y);
assert_eq!(result, vec![11, 22, 33]);
}
#[test]
fn test_zip_with_different_types() {
let numbers = vec![1, 2, 3];
let strings = vec!["a", "b", "c"];
let result = zip_with(numbers, strings, |n, s| format!("{}{}", n, s));
assert_eq!(result, vec!["1a", "2b", "3c"]);
}
#[test]
fn test_merge_two_equal_length() {
let a = vec![1, 2, 3];
let b = vec![4, 5, 6];
let result = merge(vec![a, b]);
assert_eq!(result, vec![1, 4, 2, 5, 3, 6]);
}
#[test]
fn test_merge_different_lengths() {
let a = vec![1, 2];
let b = vec![3, 4, 5, 6];
let result = merge(vec![a, b]);
assert_eq!(result, vec![1, 3, 2, 4, 5, 6]);
}
#[test]
fn test_merge_three_streams() {
let a = vec![1, 2];
let b = vec![3, 4];
let c = vec![5, 6];
let result = merge(vec![a, b, c]);
assert_eq!(result, vec![1, 3, 5, 2, 4, 6]);
}
#[test]
fn test_merge_empty_stream() {
let a = vec![1, 2, 3];
let b: Vec<i32> = vec![];
let result = merge(vec![a, b]);
assert_eq!(result, vec![1, 2, 3]);
}
#[test]
fn test_merge_single_stream() {
let a = vec![1, 2, 3];
let result = merge(vec![a]);
assert_eq!(result, vec![1, 2, 3]);
}
#[test]
fn test_merge_with_transducers() {
let pipeline_a = Map::new(|x: i32| x * 2);
let pipeline_b = Map::new(|x: i32| x + 10);
let a_result = to_vec(&pipeline_a, vec![1, 2, 3]);
let b_result = to_vec(&pipeline_b, vec![1, 2, 3]);
let merged = merge(vec![a_result, b_result]);
assert_eq!(merged, vec![2, 11, 4, 12, 6, 13]);
}
#[test]
fn test_intersection_basic() {
let a = vec![1, 2, 3, 4];
let b = vec![3, 4, 5, 6];
let result = intersection(a, b);
assert_eq!(result, vec![3, 4]);
}
#[test]
fn test_intersection_no_overlap() {
let a = vec![1, 2, 3];
let b = vec![4, 5, 6];
let result: Vec<i32> = intersection(a, b);
assert_eq!(result, Vec::<i32>::new());
}
#[test]
fn test_intersection_complete_overlap() {
let a = vec![1, 2, 3];
let b = vec![1, 2, 3];
let result = intersection(a, b);
assert_eq!(result, vec![1, 2, 3]);
}
#[test]
fn test_intersection_preserves_duplicates() {
let a = vec![1, 2, 2, 3];
let b = vec![2, 3, 4];
let result = intersection(a, b);
assert_eq!(result, vec![2, 2, 3]);
}
#[test]
fn test_intersection_with_transducers() {
let pipeline = Map::new(|x: i32| x * 2);
let a_processed = to_vec(&pipeline, vec![1, 2, 3, 4]);
let b_processed = to_vec(&pipeline, vec![3, 4, 5, 6]);
let result = intersection(a_processed, b_processed);
assert_eq!(result, vec![6, 8]); }
#[test]
fn test_difference_basic() {
let a = vec![1, 2, 3, 4];
let b = vec![3, 4, 5, 6];
let result = difference(a, b);
assert_eq!(result, vec![1, 2]);
}
#[test]
fn test_difference_no_overlap() {
let a = vec![1, 2, 3];
let b = vec![4, 5, 6];
let result = difference(a, b);
assert_eq!(result, vec![1, 2, 3]);
}
#[test]
fn test_difference_complete_overlap() {
let a = vec![1, 2, 3];
let b = vec![1, 2, 3];
let result: Vec<i32> = difference(a, b);
assert_eq!(result, Vec::<i32>::new());
}
#[test]
fn test_difference_removes_all_occurrences() {
let a = vec![1, 2, 2, 3];
let b = vec![2];
let result = difference(a, b);
assert_eq!(result, vec![1, 3]);
}
#[test]
fn test_union_basic() {
let a = vec![1, 2, 3];
let b = vec![3, 4, 5];
let result = union(a, b);
assert_eq!(result, vec![1, 2, 3, 4, 5]);
}
#[test]
fn test_union_no_overlap() {
let a = vec![1, 2, 3];
let b = vec![4, 5, 6];
let result = union(a, b);
assert_eq!(result, vec![1, 2, 3, 4, 5, 6]);
}
#[test]
fn test_union_complete_overlap() {
let a = vec![1, 2, 3];
let b = vec![1, 2, 3];
let result = union(a, b);
assert_eq!(result, vec![1, 2, 3]);
}
#[test]
fn test_union_removes_duplicates() {
let a = vec![1, 2, 2, 3];
let b = vec![3, 4, 4, 5];
let result = union(a, b);
assert_eq!(result, vec![1, 2, 3, 4, 5]);
}
#[test]
fn test_union_empty() {
let a: Vec<i32> = vec![];
let b = vec![1, 2, 3];
let result = union(a, b);
assert_eq!(result, vec![1, 2, 3]);
}
#[test]
fn test_symmetric_difference_basic() {
let a = vec![1, 2, 3, 4];
let b = vec![3, 4, 5, 6];
let result = symmetric_difference(a, b);
assert_eq!(result, vec![1, 2, 5, 6]);
}
#[test]
fn test_symmetric_difference_no_overlap() {
let a = vec![1, 2];
let b = vec![3, 4];
let result = symmetric_difference(a, b);
assert_eq!(result, vec![1, 2, 3, 4]);
}
#[test]
fn test_symmetric_difference_complete_overlap() {
let a = vec![1, 2, 3];
let b = vec![1, 2, 3];
let result: Vec<i32> = symmetric_difference(a, b);
assert_eq!(result, Vec::<i32>::new());
}
#[test]
fn test_symmetric_difference_preserves_order() {
let a = vec![4, 3, 2, 1];
let b = vec![6, 5, 2, 1];
let result = symmetric_difference(a, b);
assert_eq!(result, vec![4, 3, 6, 5]);
}
#[test]
fn test_symmetric_difference_duplicates() {
let a = vec![1, 1, 2, 3];
let b = vec![3, 4, 4];
let result = symmetric_difference(a, b);
assert_eq!(result, vec![1, 2, 4]);
}
#[test]
fn test_take_last_basic() {
use crate::transducer::Identity;
let id = Identity::new();
let result = take_last(&id, vec![1, 2, 3, 4, 5], 3);
assert_eq!(result, vec![3, 4, 5]);
}
#[test]
fn test_take_last_more_than_available() {
use crate::transducer::Identity;
let id = Identity::new();
let result = take_last(&id, vec![1, 2, 3], 10);
assert_eq!(result, vec![1, 2, 3]);
}
#[test]
fn test_take_last_zero() {
use crate::transducer::Identity;
let id = Identity::new();
let result = take_last(&id, vec![1, 2, 3, 4, 5], 0);
assert_eq!(result, Vec::<i32>::new());
}
#[test]
fn test_take_last_with_transducer() {
let pipeline = Map::new(|x: i32| x * 2);
let result = take_last(&pipeline, vec![1, 2, 3, 4, 5], 2);
assert_eq!(result, vec![8, 10]); }
#[test]
fn test_drop_last_basic() {
use crate::transducer::Identity;
let id = Identity::new();
let result = drop_last(&id, vec![1, 2, 3, 4, 5], 2);
assert_eq!(result, vec![1, 2, 3]);
}
#[test]
fn test_drop_last_more_than_available() {
use crate::transducer::Identity;
let id = Identity::new();
let result = drop_last(&id, vec![1, 2, 3], 10);
assert_eq!(result, Vec::<i32>::new());
}
#[test]
fn test_drop_last_zero() {
use crate::transducer::Identity;
let id = Identity::new();
let result = drop_last(&id, vec![1, 2, 3, 4, 5], 0);
assert_eq!(result, vec![1, 2, 3, 4, 5]);
}
#[test]
fn test_drop_last_with_transducer() {
let pipeline = Map::new(|x: i32| x * 2);
let result = drop_last(&pipeline, vec![1, 2, 3, 4, 5], 2);
assert_eq!(result, vec![2, 4, 6]); }
#[test]
fn test_take_last_empty() {
use crate::transducer::Identity;
let id = Identity::new();
let result = take_last(&id, Vec::<i32>::new(), 5);
assert_eq!(result, Vec::<i32>::new());
}
#[test]
fn test_drop_last_empty() {
use crate::transducer::Identity;
let id = Identity::new();
let result = drop_last(&id, Vec::<i32>::new(), 5);
assert_eq!(result, Vec::<i32>::new());
}
#[test]
fn test_take_last_one() {
use crate::transducer::Identity;
let id = Identity::new();
let result = take_last(&id, vec![1, 2, 3, 4, 5], 1);
assert_eq!(result, vec![5]);
}
#[test]
fn test_take_last_all() {
use crate::transducer::Identity;
let id = Identity::new();
let result = take_last(&id, vec![1, 2, 3], 3);
assert_eq!(result, vec![1, 2, 3]);
}
#[test]
fn test_take_last_single_element() {
use crate::transducer::Identity;
let id = Identity::new();
let result = take_last(&id, vec![42], 1);
assert_eq!(result, vec![42]);
}
#[test]
fn test_take_last_with_filter() {
let pipeline = Filter::new(|x: &i32| x % 2 == 0);
let result = take_last(&pipeline, vec![1, 2, 3, 4, 5, 6, 7, 8], 2);
assert_eq!(result, vec![6, 8]); }
#[test]
fn test_take_last_strings() {
use crate::transducer::Identity;
let id = Identity::new();
let result = take_last(&id, vec!["a", "b", "c", "d"], 2);
assert_eq!(result, vec!["c", "d"]);
}
#[test]
fn test_take_last_large_data() {
use crate::transducer::Identity;
let id = Identity::new();
let data: Vec<i32> = (1..=1000).collect();
let result = take_last(&id, data, 10);
assert_eq!(
result,
vec![991, 992, 993, 994, 995, 996, 997, 998, 999, 1000]
);
}
#[test]
fn test_take_last_composed_operations() {
let pipeline = Map::new(|x: i32| x * x);
let result = take_last(&pipeline, vec![1, 2, 3, 4, 5], 3);
assert_eq!(result, vec![9, 16, 25]);
}
#[test]
fn test_drop_last_one() {
use crate::transducer::Identity;
let id = Identity::new();
let result = drop_last(&id, vec![1, 2, 3, 4, 5], 1);
assert_eq!(result, vec![1, 2, 3, 4]);
}
#[test]
fn test_drop_last_all() {
use crate::transducer::Identity;
let id = Identity::new();
let result = drop_last(&id, vec![1, 2, 3], 3);
assert_eq!(result, Vec::<i32>::new());
}
#[test]
fn test_drop_last_single_element() {
use crate::transducer::Identity;
let id = Identity::new();
let result = drop_last(&id, vec![42], 1);
assert_eq!(result, Vec::<i32>::new());
}
#[test]
fn test_drop_last_with_filter() {
let pipeline = Filter::new(|x: &i32| x % 2 == 0);
let result = drop_last(&pipeline, vec![1, 2, 3, 4, 5, 6, 7, 8], 2);
assert_eq!(result, vec![2, 4]); }
#[test]
fn test_drop_last_strings() {
use crate::transducer::Identity;
let id = Identity::new();
let result = drop_last(&id, vec!["a", "b", "c", "d"], 2);
assert_eq!(result, vec!["a", "b"]);
}
#[test]
fn test_drop_last_large_data() {
use crate::transducer::Identity;
let id = Identity::new();
let data: Vec<i32> = (1..=1000).collect();
let result = drop_last(&id, data, 10);
assert_eq!(result.len(), 990);
assert_eq!(result[0], 1);
assert_eq!(result[989], 990);
}
#[test]
fn test_drop_last_composed_operations() {
let pipeline = Map::new(|x: i32| x * x);
let result = drop_last(&pipeline, vec![1, 2, 3, 4, 5], 2);
assert_eq!(result, vec![1, 4, 9]); }
#[test]
fn test_take_last_drop_last_equivalence() {
use crate::transducer::Identity;
let id = Identity::new();
let data = vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
let taken = take_last(&id, data.clone(), 3);
let remaining_after_drop_first: Vec<i32> = data.iter().skip(7).cloned().collect();
assert_eq!(taken, remaining_after_drop_first);
}
#[test]
fn test_drop_last_take_last_coverage() {
use crate::transducer::Identity;
let id = Identity::new();
let data = vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
let dropped = drop_last(&id, data.clone(), 3);
let taken = take_last(&id, data, 3);
assert_eq!(dropped.len() + taken.len(), 10);
assert_eq!(dropped, vec![1, 2, 3, 4, 5, 6, 7]);
assert_eq!(taken, vec![8, 9, 10]);
}
#[test]
fn test_product_basic() {
use crate::transducer::Identity;
let id = Identity::new();
let result = product(&id, vec![2, 3, 4]);
assert_eq!(result, 24);
}
#[test]
fn test_product_empty() {
use crate::transducer::Identity;
let id = Identity::new();
let result: i32 = product(&id, Vec::<i32>::new());
assert_eq!(result, 1); }
#[test]
fn test_product_with_map() {
let double = Map::new(|x: i32| x * 2);
let result = product(&double, vec![1, 2, 3]);
assert_eq!(result, 48); }
#[test]
fn test_product_with_zero() {
use crate::transducer::Identity;
let id = Identity::new();
let result = product(&id, vec![1, 2, 0, 3, 4]);
assert_eq!(result, 0);
}
#[test]
fn test_mean_basic() {
use crate::transducer::Identity;
let id = Identity::new();
let result = mean(&id, vec![1.0, 2.0, 3.0, 4.0, 5.0]);
assert_eq!(result, Some(3.0));
}
#[test]
fn test_mean_empty() {
use crate::transducer::Identity;
let id = Identity::new();
let result = mean(&id, Vec::<f64>::new());
assert_eq!(result, None);
}
#[test]
fn test_mean_integers() {
use crate::transducer::Identity;
let id = Identity::new();
let result = mean(&id, vec![1, 2, 3, 4, 5]);
assert_eq!(result, Some(3.0));
}
#[test]
fn test_mean_with_map() {
let double = Map::new(|x: i32| (x * 2) as f64);
let result = mean(&double, vec![1, 2, 3, 4, 5]);
assert_eq!(result, Some(6.0)); }
#[test]
fn test_median_odd_count() {
use crate::transducer::Identity;
let id = Identity::new();
let result = median(&id, vec![1.0, 2.0, 3.0, 4.0, 5.0]);
assert_eq!(result, Some(3.0));
}
#[test]
fn test_median_even_count() {
use crate::transducer::Identity;
let id = Identity::new();
let result = median(&id, vec![1.0, 2.0, 3.0, 4.0]);
assert_eq!(result, Some(2.5));
}
#[test]
fn test_median_empty() {
use crate::transducer::Identity;
let id = Identity::new();
let result = median(&id, Vec::<f64>::new());
assert_eq!(result, None);
}
#[test]
fn test_median_single() {
use crate::transducer::Identity;
let id = Identity::new();
let result = median(&id, vec![42.0]);
assert_eq!(result, Some(42.0));
}
#[test]
fn test_median_unsorted() {
use crate::transducer::Identity;
let id = Identity::new();
let result = median(&id, vec![5.0, 1.0, 3.0, 2.0, 4.0]);
assert_eq!(result, Some(3.0));
}
#[test]
fn test_min_basic() {
use crate::transducer::Identity;
let id = Identity::new();
let result = min(&id, vec![3, 1, 4, 1, 5]);
assert_eq!(result, Some(1));
}
#[test]
fn test_min_empty() {
use crate::transducer::Identity;
let id = Identity::new();
let result = min(&id, Vec::<i32>::new());
assert_eq!(result, None);
}
#[test]
fn test_min_with_map() {
let double = Map::new(|x: i32| x * 2);
let result = min(&double, vec![3, 1, 4, 1, 5]);
assert_eq!(result, Some(2)); }
#[test]
fn test_max_basic() {
use crate::transducer::Identity;
let id = Identity::new();
let result = max(&id, vec![3, 1, 4, 1, 5]);
assert_eq!(result, Some(5));
}
#[test]
fn test_max_empty() {
use crate::transducer::Identity;
let id = Identity::new();
let result = max(&id, Vec::<i32>::new());
assert_eq!(result, None);
}
#[test]
fn test_max_with_map() {
let double = Map::new(|x: i32| x * 2);
let result = max(&double, vec![3, 1, 4, 1, 5]);
assert_eq!(result, Some(10)); }
#[test]
fn test_min_by_basic() {
use crate::transducer::Identity;
#[derive(Debug, PartialEq, Clone)]
struct Product {
name: &'static str,
price: i32,
}
let id = Identity::new();
let products = vec![
Product {
name: "Apple",
price: 100,
},
Product {
name: "Banana",
price: 50,
},
Product {
name: "Cherry",
price: 150,
},
];
let cheapest = min_by(&id, products, |p| p.price);
assert_eq!(cheapest.unwrap().name, "Banana");
}
#[test]
fn test_min_by_empty() {
use crate::transducer::Identity;
#[derive(Debug, PartialEq)]
struct Item {
value: i32,
}
let id = Identity::new();
let result = min_by(&id, Vec::<Item>::new(), |item| item.value);
assert_eq!(result, None);
}
#[test]
fn test_max_by_basic() {
use crate::transducer::Identity;
#[derive(Debug, PartialEq, Clone)]
struct Product {
name: &'static str,
price: i32,
}
let id = Identity::new();
let products = vec![
Product {
name: "Apple",
price: 100,
},
Product {
name: "Banana",
price: 50,
},
Product {
name: "Cherry",
price: 150,
},
];
let most_expensive = max_by(&id, products, |p| p.price);
assert_eq!(most_expensive.unwrap().name, "Cherry");
}
#[test]
fn test_max_by_empty() {
use crate::transducer::Identity;
#[derive(Debug, PartialEq)]
struct Item {
value: i32,
}
let id = Identity::new();
let result = max_by(&id, Vec::<Item>::new(), |item| item.value);
assert_eq!(result, None);
}
#[test]
fn test_variance_basic() {
use crate::transducer::Identity;
let id = Identity::new();
let result = variance(&id, vec![2.0, 4.0, 4.0, 4.0, 5.0, 5.0, 7.0, 9.0]);
assert!((result.unwrap() - 4.571).abs() < 0.01);
}
#[test]
fn test_variance_empty() {
use crate::transducer::Identity;
let id = Identity::new();
let result = variance(&id, Vec::<f64>::new());
assert_eq!(result, None);
}
#[test]
fn test_variance_single_element() {
use crate::transducer::Identity;
let id = Identity::new();
let result = variance(&id, vec![42.0]);
assert_eq!(result, None); }
#[test]
fn test_variance_two_elements() {
use crate::transducer::Identity;
let id = Identity::new();
let result = variance(&id, vec![1.0, 3.0]);
assert!((result.unwrap() - 2.0).abs() < 0.0001);
}
#[test]
fn test_std_dev_basic() {
use crate::transducer::Identity;
let id = Identity::new();
let result = std_dev(&id, vec![2.0, 4.0, 4.0, 4.0, 5.0, 5.0, 7.0, 9.0]);
assert!((result.unwrap() - 2.138).abs() < 0.01);
}
#[test]
fn test_std_dev_empty() {
use crate::transducer::Identity;
let id = Identity::new();
let result = std_dev(&id, Vec::<f64>::new());
assert_eq!(result, None);
}
#[test]
fn test_std_dev_constant() {
use crate::transducer::Identity;
let id = Identity::new();
let result = std_dev(&id, vec![5.0, 5.0, 5.0, 5.0]);
assert!((result.unwrap() - 0.0).abs() < 0.0001);
}
#[test]
fn test_quantile_median() {
use crate::transducer::Identity;
let id = Identity::new();
let result = quantile(&id, vec![1.0, 2.0, 3.0, 4.0, 5.0], 0.5);
assert_eq!(result, Some(3.0));
}
#[test]
fn test_quantile_min() {
use crate::transducer::Identity;
let id = Identity::new();
let result = quantile(&id, vec![1.0, 2.0, 3.0, 4.0, 5.0], 0.0);
assert_eq!(result, Some(1.0));
}
#[test]
fn test_quantile_max() {
use crate::transducer::Identity;
let id = Identity::new();
let result = quantile(&id, vec![1.0, 2.0, 3.0, 4.0, 5.0], 1.0);
assert_eq!(result, Some(5.0));
}
#[test]
fn test_quantile_p95() {
use crate::transducer::Identity;
let id = Identity::new();
let result = quantile(&id, vec![1.0, 2.0, 3.0, 4.0, 5.0], 0.95);
assert_eq!(result, Some(4.8));
}
#[test]
fn test_quantile_empty() {
use crate::transducer::Identity;
let id = Identity::new();
let result = quantile(&id, Vec::<f64>::new(), 0.5);
assert_eq!(result, None);
}
#[test]
fn test_quantile_invalid_p() {
use crate::transducer::Identity;
let id = Identity::new();
assert_eq!(quantile(&id, vec![1.0, 2.0, 3.0], -0.1), None);
assert_eq!(quantile(&id, vec![1.0, 2.0, 3.0], 1.5), None);
}
#[test]
fn test_quantile_single_element() {
use crate::transducer::Identity;
let id = Identity::new();
let result = quantile(&id, vec![42.0], 0.5);
assert_eq!(result, Some(42.0));
}
#[test]
fn test_mode_basic() {
use crate::transducer::Identity;
let id = Identity::new();
let result = mode(&id, vec![1, 2, 2, 3, 3, 3, 4]);
assert_eq!(result, Some(3));
}
#[test]
fn test_mode_empty() {
use crate::transducer::Identity;
let id = Identity::new();
let result = mode(&id, Vec::<i32>::new());
assert_eq!(result, None);
}
#[test]
fn test_mode_all_unique() {
use crate::transducer::Identity;
let id = Identity::new();
let result = mode(&id, vec![1, 2, 3, 4, 5]);
assert!(result.is_some());
assert!([1, 2, 3, 4, 5].contains(&result.unwrap()));
}
#[test]
fn test_mode_with_map() {
let mod_3 = Map::new(|x: i32| x % 3);
let result = mode(&mod_3, vec![3, 6, 9, 12, 1, 2]);
assert_eq!(result, Some(0));
}
#[test]
fn test_mode_strings() {
use crate::transducer::Identity;
let id = Identity::new();
let result = mode(&id, vec!["a", "b", "a", "c", "a", "b"]);
assert_eq!(result, Some("a"));
}
#[test]
fn test_statistical_operations_pipeline() {
use crate::transducer::Identity;
let id = Identity::new();
let data = vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
assert_eq!(mean(&id, data.clone()), Some(5.5));
assert_eq!(median(&id, data.clone()), Some(5.5));
assert_eq!(min(&id, data.clone()), Some(1));
assert_eq!(max(&id, data.clone()), Some(10));
}
#[test]
fn test_phase4_with_filter() {
let pipeline = Filter::new(|x: &i32| x % 2 == 0);
let data = vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
assert_eq!(count(&pipeline, data.clone()), 5);
assert_eq!(sum(&pipeline, data.clone()), 30); assert_eq!(product(&pipeline, data.clone()), 3840); assert_eq!(mean(&pipeline, data.clone()), Some(6.0));
assert_eq!(min(&pipeline, data.clone()), Some(2));
assert_eq!(max(&pipeline, data.clone()), Some(10));
}
#[test]
fn test_sort_by_basic() {
use crate::transducer::Identity;
#[derive(Debug, Clone, PartialEq)]
struct Person {
name: &'static str,
age: i32,
}
let id = Identity::new();
let people = vec![
Person {
name: "Alice",
age: 30,
},
Person {
name: "Bob",
age: 25,
},
Person {
name: "Charlie",
age: 35,
},
];
let sorted = sort_by(&id, people, |p| p.age);
assert_eq!(sorted[0].name, "Bob");
assert_eq!(sorted[1].name, "Alice");
assert_eq!(sorted[2].name, "Charlie");
}
#[test]
fn test_sort_by_empty() {
use crate::transducer::Identity;
let id = Identity::new();
let result: Vec<i32> = sort_by(&id, Vec::<i32>::new(), |x| *x);
assert_eq!(result, Vec::<i32>::new());
}
#[test]
fn test_sort_by_with_map() {
let pipeline = Map::new(|x: i32| x * x);
let result = sort_by(&pipeline, vec![3, 1, 4, 2], |x| *x);
assert_eq!(result, vec![1, 4, 9, 16]);
}
#[test]
fn test_sort_with_descending() {
use crate::transducer::Identity;
let id = Identity::new();
let numbers = vec![3, 1, 4, 1, 5, 9, 2, 6];
let sorted = sort_with(&id, numbers, |a, b| b.cmp(a));
assert_eq!(sorted, vec![9, 6, 5, 4, 3, 2, 1, 1]);
}
#[test]
fn test_sort_with_ascending() {
use crate::transducer::Identity;
let id = Identity::new();
let numbers = vec![3, 1, 4, 1, 5, 9, 2, 6];
let sorted = sort_with(&id, numbers, |a, b| a.cmp(b));
assert_eq!(sorted, vec![1, 1, 2, 3, 4, 5, 6, 9]);
}
#[test]
fn test_reverse_basic() {
use crate::transducer::Identity;
let id = Identity::new();
let result = reverse(&id, vec![1, 2, 3, 4, 5]);
assert_eq!(result, vec![5, 4, 3, 2, 1]);
}
#[test]
fn test_reverse_empty() {
use crate::transducer::Identity;
let id = Identity::new();
let result: Vec<i32> = reverse(&id, Vec::<i32>::new());
assert_eq!(result, Vec::<i32>::new());
}
#[test]
fn test_reverse_single() {
use crate::transducer::Identity;
let id = Identity::new();
let result = reverse(&id, vec![42]);
assert_eq!(result, vec![42]);
}
#[test]
fn test_reverse_with_map() {
let double = Map::new(|x: i32| x * 2);
let result = reverse(&double, vec![1, 2, 3, 4, 5]);
assert_eq!(result, vec![10, 8, 6, 4, 2]);
}
#[test]
fn test_range_basic() {
let result = range(0, 10, 1);
assert_eq!(result, vec![0, 1, 2, 3, 4, 5, 6, 7, 8, 9]);
}
#[test]
fn test_range_step_2() {
let evens = range(0, 20, 2);
assert_eq!(evens, vec![0, 2, 4, 6, 8, 10, 12, 14, 16, 18]);
}
#[test]
fn test_range_descending() {
let desc = range(10, 0, -1);
assert_eq!(desc, vec![10, 9, 8, 7, 6, 5, 4, 3, 2, 1]);
}
#[test]
fn test_range_empty() {
let result = range(0, 0, 1);
assert_eq!(result, Vec::<i32>::new());
}
#[test]
fn test_range_negative_step() {
let result = range(5, 0, -2);
assert_eq!(result, vec![5, 3, 1]);
}
#[test]
#[should_panic(expected = "Step cannot be zero")]
fn test_range_zero_step() {
range(0, 10, 0);
}
#[test]
fn test_repeat_basic() {
let zeros = repeat(0, 5);
assert_eq!(zeros, vec![0, 0, 0, 0, 0]);
}
#[test]
fn test_repeat_strings() {
let words = repeat("hello", 3);
assert_eq!(words, vec!["hello", "hello", "hello"]);
}
#[test]
fn test_repeat_zero() {
let result: Vec<i32> = repeat(42, 0);
assert_eq!(result, Vec::<i32>::new());
}
#[test]
fn test_cycle_basic() {
let pattern = cycle(vec![1, 2, 3], 3);
assert_eq!(pattern, vec![1, 2, 3, 1, 2, 3, 1, 2, 3]);
}
#[test]
fn test_cycle_strings() {
let repeated = cycle(vec!["a", "b"], 2);
assert_eq!(repeated, vec!["a", "b", "a", "b"]);
}
#[test]
fn test_cycle_zero() {
let result: Vec<i32> = cycle(vec![1, 2, 3], 0);
assert_eq!(result, Vec::<i32>::new());
}
#[test]
fn test_cycle_empty_vec() {
let result: Vec<i32> = cycle(Vec::new(), 5);
assert_eq!(result, Vec::<i32>::new());
}
#[test]
fn test_unfold_powers_of_2() {
let powers = unfold(
1,
|x| {
let next = x * 2;
if next <= 1000 {
Some(next)
} else {
None
}
},
20,
);
assert_eq!(powers, vec![2, 4, 8, 16, 32, 64, 128, 256, 512]);
}
#[test]
fn test_unfold_countdown() {
let countdown = unfold(5, |x| if *x > 0 { Some(x - 1) } else { None }, 10);
assert_eq!(countdown, vec![4, 3, 2, 1, 0]);
}
#[test]
fn test_unfold_limit() {
let result = unfold(1, |x| Some(x + 1), 5);
assert_eq!(result, vec![2, 3, 4, 5, 6]);
}
#[test]
fn test_unfold_early_stop() {
let result: Vec<i32> = unfold(1, |_x| None, 10);
assert_eq!(result, Vec::<i32>::new());
}
#[test]
fn test_unfold_fibonacci() {
let fibonacci = unfold(
(0, 1),
|(a, b)| {
let next = (*b, a + b);
if next.0 <= 100 {
Some(next)
} else {
None
}
},
20,
);
let fib_numbers: Vec<i32> = fibonacci.iter().map(|(a, _)| *a).collect();
assert_eq!(fib_numbers, vec![1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89]);
}
#[test]
fn test_phase5_integration() {
use crate::transducer::Identity;
let id = Identity::new();
let numbers = range(1, 11, 1);
let pipeline = Filter::new(|x: &i32| x % 2 == 0);
let evens = to_vec(&pipeline, numbers);
let sorted = sort_with(&id, evens, |a, b| b.cmp(a));
let reversed = reverse(&id, sorted);
assert_eq!(reversed, vec![2, 4, 6, 8, 10]);
}
#[test]
fn test_phase5_cycle_with_transducer() {
let pattern = cycle(vec![1, 2, 3], 2);
let double = Map::new(|x: i32| x * 2);
let result = to_vec(&double, pattern);
assert_eq!(result, vec![2, 4, 6, 2, 4, 6]);
}
}