C++ Streams

Streams is a C++14 library that provides lazy evaluation and functional-style transformations on the data, to ease the use of C++ standard library containers and algorithms. Streams support many common functional operations such as map, filter, and reduce, as well as various others. Please see the API reference for complete details.

To use streams download them from Github. To use, simply #include "Stream.h". Streams require C++14 to compile. Streams consist only of header files, so you shouldn't have to modify your build process to use them.

Examples

(Note: In all of the examples, assume we are using the namespaces stream and stream::op). Summing the first 10 squares:
int total = MakeStream::counter(1)
    | map_([] (int x) { return x * x; })
    | limit(10)
    | sum();
Investigating the collatz conjecture:
auto next_collatz = [] (int n) {
    if(n % 2 == 0)
        return n / 2;
    else
        return 3 * n + 1;
};

int distance = MakeStream::generate(1124, next_collatz)
    | take_while([] (int n) { return n != 1; })
    | count();
Running a coin flip experiment:
int heads = MakeStream::coin_flips() // Uniform random bools
    | limit(1000) // Take the first 1000 coin flips
    | filter()    // Take only the true ones (heads)
    | count();
Extracting values from objects and handling them:
std::vector<Widget> widgets = /* ... */
std::set<int> ids = MakeStream::from(widgets)
    | map_(&Widget::getId)
    | to_set();
Getting summary statistics from a set of data:
std::vector<Widget> widgets = /* ... */
auto stats = MakeStream::from(widgets)
    | map_(&Widget::getValue)
    | reducers::SummaryStats<double>().reducer();
std::cout << "Mean   = " << stats.mean()   << "\n"
          << "StdDev = " << stats.stddev() << "\n"
          << "Min    = " << stats.min()    << "\n"
          << "Max    = " << stats.max()    << "\n"
          << "Number = " << stats.num()    << std::endl;
Set operations. Instead of having to do this:
std::set<Gadget> left = /* ... */
std::set<Gadget> right = /* ... */
std::set<Gadget> result;

std::set_intersection(left.begin(), left.end(),
                      right.begin(), right.end()
                      std::inserter(result, result.end());
We can now do this much more readably:
std::set<Gadget> left = /* ... */
std::set<Gadget> right = /* ... */

std::set<Gadget> result = Stream<Gadget>(left)
    | intersect_with(Stream<Gadget>(right))
    | to_set();
Vector operations:
std::vector<double> vec1 = /* ... */
std::vector<double> vec2 = /* ... */

auto stream = [](auto& x) {
    return MakeStream::from(x);
};

auto sum = (stream(vec1) + stream(vec2)) | to_vector();
auto scale = (stream(vec1) * 5) | to_vector();
auto translate = (stream(vec1) + 10) | to_vector();
double dot_product = (stream(vec1) * stream(vec2)) | sum();
Operator composition:
auto square = map_([](auto&& x) { return x * x; });
MakeStream::range(1, 5) | square | print_to(std::cout) // 1 4 9 16

auto square_and_sum = square | sum();
int result = MakeStream::range(1, 4) | square_and_sum; // 14

auto every_nth = [](int n) {
    return zip_with(MakeStream::counter(0))
         | filter([=](const auto& tup) {
            return std::get<1>(tup) % n == 0;
        })
         | map_([](auto&& tup) {
            return std::get<0>(tup);
        });
};

MakeStream::from({1, 3, 8, 4, 7})
    | every_nth(2)
    | print_to(std::cout); // 1 8 7

For more complete information, see the API reference.

C++ Streams is developed by Jonah Scheinerman and is always looking to improve. Please contact me if you have question, concerns, bugs, or ideas on how to make streams even better.

C++ Streams are distributed under the MIT open source license.

Copyright © 2014 by Jonah Scheinerman