reductor 0.0.2

Generic abstractions for combining and nesting reduction patterns for iterables.
Documentation

Generic abstractions for combining and nesting reduction patterns for iterables.

The main entry point to this library is Reduce::reduce_with, which can be called on any Iterator, and is very similar to Iterator::reduce, but uses a generic implementation of a Reductor for the reduction logic.

The following examples shows some of the basic building blocks from which reductor enables building more complex patterns:

use reductor::{Reduce, Sum, Product, Count, Min, Max};

let iter = 0..10;

let Sum(sum) = iter.clone().reduce_with::<Sum<u32>>();
let Product(product) = iter.clone().reduce_with::<Product<u32>>();
let Count(count) = iter.clone().reduce_with();
assert_eq!(sum, iter.clone().sum());
assert_eq!(product, iter.clone().product());
assert_eq!(count, iter.clone().count());

let Max(max) = iter.clone().reduce_with::<Max<Option<u32>>>();
let Min(min) = iter.clone().reduce_with::<Min<Option<u32>>>();
assert_eq!(max, Some(9));
assert_eq!(min, Some(0));

Notice that unlike Sum and Product, Min and Max won't reduce an empty iterator into the default value. This mirrors the way Iterator::max returns an Option<T>, unlike Iterator::sum.

Now, let's combine two Reductors to reduce an iterator that produces a pair of values:

use reductor::{Reduce, Sum, Product};

let iter = 0..10;
let (Sum(sum), Product(product)) = iter
    .clone()
    .map(|x| (x, x * 2))
    .reduce_with::<(Sum<usize>, Product<usize>)>();

assert_eq!(sum, iter.clone().sum());
assert_eq!(product, iter.map(|x| x * 2).product());

Another abstraction provided by this library is ReductorPair, which allows reducing an iterator producing a single value by a pair of Reductors, in tandem.

use reductor::{Reduce, ReductorPair, Sum, Max};

let iter = 0..10;
let ReductorPair(Max(max), Sum(sum)) = iter
    .clone()
    .map(|x| x)
    .reduce_with::<Option<ReductorPair<Max<usize>, Sum<usize>>>>().unwrap();

assert_eq!(sum, iter.clone().sum());
assert_eq!(max, iter.clone().max().unwrap());

These constructs allow building very complex iterator loops that compose numerous reductions into a single set of results.

use reductor::{Reduce, ReductorPair, Count, Sum, Product, Max, Min};

let iter = (0_i32..100).filter_map(|x| {
    if x % 2 == 0 {
        None
    } else {
        Some((x, x.leading_zeros()))
    }
});

let ReductorPair(Count(count), (Sum(sum), ReductorPair(Min(min), Max(max)))) = iter
    .clone()
    .reduce_with::<Option<ReductorPair<Count, (Sum<i32>, ReductorPair<Min<u32>, Max<u32>>)>>>().unwrap();

assert_eq!(count, iter.clone().count());
assert_eq!(sum, iter.clone().map(|(x, ..)| x).sum());
assert_eq!(min, iter.clone().map(|(.., x)| x).min().unwrap());
assert_eq!(max, iter.map(|(.., x)| x).max().unwrap());