SCHEDULED DOWNTIME: GitLab's virtual host needs to be rebooted in order to apply security updates. The reboot will occur on Wednesday 2021-10-18 between 03:45 and 4:00 AM.

Commit 945562e8 authored by Jan Koniarik's avatar Jan Koniarik
Browse files

finished v1 of examples for algorithm

parent a9a644aa
Pipeline #95334 passed with stage
in 37 seconds
#include "emlabcpp/algorithm.h"
#include <ctime>
#include <iostream>
#include <list>
#include <string>
namespace em = emlabcpp;
......@@ -9,14 +10,16 @@ int main(int, char *[]) {
std::srand(static_cast<unsigned>(std::time(nullptr)));
// ---------------------------------------------------------------------------------------
// datastructures used in the example
// data structures used in the examples
std::tuple<int, std::string> tpl_data{42, "wololo"};
std::vector<int> vec_data{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 0};
std::list<int> list_data{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 0};
// ---------------------------------------------------------------------------------------
// one of the two basic algorithms - for_each, the crucial property of both these is that
// they have overload for both - begin/end containers and std::tuple-like data.
// `for_each(cont, f)` simply executes lambda `f` over each item in container `cont`, the
// crucial property is that container can be either begin/end container or std::tuple-like
// container. This is used to implement algorithms that work over both types of containers.
em::for_each(tpl_data, [&](const auto &item) {
std::cout << item << '\n';
......@@ -27,8 +30,9 @@ int main(int, char *[]) {
});
// ---------------------------------------------------------------------------------------
// seocnd of the two basic algorithms - find_if, again it exists in version for tuples and
// containers. The tuple version returns index of item that matched the predicate.
// `find_if(cont,f)` is used to find first item in container `cont` that satisfies predicate
// `f`. This returns index of item for std::tuple-like items and iterator for begin/end
// containers.
std::size_t index = em::find_if(tpl_data, [&](auto item) {
return std::is_same_v<decltype(item), std::string>;
......@@ -38,19 +42,19 @@ int main(int, char *[]) {
auto iter = em::find_if(vec_data, [&](int i) {
return i == 0;
});
std::cout << "Zero item is at pos: " << std::distance(iter, vec_data.begin()) << '\n';
std::cout << "Zero item is at position: " << std::distance(iter, vec_data.begin()) << '\n';
// ---------------------------------------------------------------------------------------
// Basic set of handy functions contains `ignore(val)` to shutdown compilers error with
// unused variable - just call ignore() over it, it does nothing.
// `ignore(x)` does nothing to the value `x`. Use it to shut down the compiler warning for
// unused variable in situations that requires it.
int unused_variable = 0;
em::ignore(unused_variable);
// ---------------------------------------------------------------------------------------
// `sign(x)` is function that returns an int representing sign of x, that you can do to
// implement more processing based on it, or multiply different value to mirror sign (such
// as sign(x)*y). Keep in mind that it returns 0 for 0 input value.
// `sign(x)` is used to indicate a sign of variables required for some algorithms. It can be
// used to either explicitly control flow based on the sign or use it to propagate the sign
// into a computation. Note that we consider 0 as a separate case.
int sign_rand_val = (std::rand() % 3) - 1;
switch (em::sign(sign_rand_val)) {
......@@ -71,63 +75,145 @@ int main(int, char *[]) {
// 0-100% intensity.
float mapped = em::map_range(42, 0, 255, 0.0f, 1.0f);
std::cout << "42 mapped from range 0-255 to range 0.-1. is: " << mapped << "\n";
std::cout << "42 mapped from range 0-255 to range 0-1, is: " << mapped << '\n';
// ---------------------------------------------------------------------------------------
// `almost_equal(a,b,e)` is used to check that `a` and `b` is close enough to each other, in
// situations where equality is not expected or problematic (floats...). `e` is tolerance
// value.
// situations where equality is not expected or problematic (floats...). `e` specifies
// tolerable range
if (em::almost_equal(0.0f, 0.1f, 0.5)) {
std::cout << "Yaaaay, 0.1 is within a tolerance of 0.5 to 0.\n";
}
// ---------------------------------------------------------------------------------------
// `tail` returns a view over provided container without the first item, handy for the code
// that handles first item differently.
// `tail(cont)` returns a view over provided container without the first item, handy for the
// code that handles first item differently.
for (int i : em::tail(vec_data)) {
std::cout << i << '\n'; // note that `1` from the container is ignored
}
// ---------------------------------------------------------------------------------------
// `init` returns a view over provided container without the last item, handy for the code
// that handles last item differently.
// `init(cont)` returns a view over provided container without the last item, handy for the
// code that handles last item differently.
for (int i : em::init(vec_data)) {
std::cout << i << '\n'; // note that `0` from the container is ignored
}
// ---------------------------------------------------------------------------------------
// `min_max_elem` gives you abillity to find minimal amd maximal value of some calculation
// applied to each item of container - such as min/max absolute value of integers in vector.
// `min_max_elem(cont, f)` is used to find minimal and maximal value of some
// calculation applied to each item of container - such as min/max absolute value of
// integers in vector.
//
// There also exists min_elem and max_elem for calculation just part of it.
// There also exists `min_elem` and `max_elem`.
em::min_max<int> mm_res = em::min_max_elem(vec_data, [](int val) {
return em::abs(val);
});
std::cout << "Minimal absolute value of vec_data is " << mm_res.min << " and maximum is "
<< mm_res.max << "\n";
<< mm_res.max << '\n';
// ---------------------------------------------------------------------------------------
// `sum` is function that can be used to '+=' data from container (where third argument is
// optional default value) and apply function to them at the same time. Usefull for
// calculation sums in math sense.
// `sum(cont, f)` returns sum of result of `f` applied over container `cont`, useful to
// mirror sum in mathematical sense.
int squared_sum = em::sum(vec_data, [](int val) {
return val * val;
});
std::cout << "Squared sum of values from vector is: " << squared_sum << "\n";
std::cout << "Squared sum of values from vector is: " << squared_sum << '\n';
// ---------------------------------------------------------------------------------------
// `accumulate` gets a container `c` and folds function `f` over it with first value being
// 's', this forms f(f(f(f(s,c[0]),c[1]),c[2])... chain Usefull for for implementing `sum`
// or doing multiplication instead.
// `accumulate(cont, f)` gets a container `c` and folds function `f` over it with first
// value being 's', this forms `f(f(f(f(s,c[0]),c[1]),c[2])...` chain. Useful for for
// implementing `sum` or doing multiplication instead.
int multiplied_vec = em::accumulate(vec_data, 1, [](int base, int val) {
return base * val;
});
std::cout << "Value of all values in vector multiplied together is: " << multiplied_vec
<< "\n";
<< '\n';
// ---------------------------------------------------------------------------------------
// `avg(cont, f)` can be used to calculate average value of items, with function
// pre-processing them.
float avg_vec = em::avg(vec_data, [&](int val) {
return static_cast<float>(val);
});
std::cout << "Average value of items in vec_data is: " << avg_vec << '\n';
// ---------------------------------------------------------------------------------------
// for_cross_joint(a,b,f) applies `f` to all combinations of values, used for combinational
// stuff and generation of data
em::for_cross_joint(tpl_data, vec_data, [](auto tpl_val, int vec_val) {
std::cout << "tpl val: " << tpl_val << " vec val: " << vec_val << '\n';
});
// ---------------------------------------------------------------------------------------
// `any_of(cont, f)` returns true if the lambda evaluates at true to at least one item in
// the container. This can be used for checking various properties over container, there is
// also `none_of(cont, f)` and `all_of(cont, f)`
bool has_zero_val = em::any_of(vec_data, [](int val) {
return val == 0;
});
if (has_zero_val) {
std::cout << "there is zero in vec_data \\o/ \n";
}
// ---------------------------------------------------------------------------------------
// `equal(cont1, cont2)` compares content of containers for equality, this avoids the need
// for same types of containers or values.
bool content_is_equal = em::equal(vec_data, list_data);
std::cout << "The statement that vec_data and list_data has equal content is: "
<< (content_is_equal ? "true" : "false") << '\n';
// ---------------------------------------------------------------------------------------
// `map_f(cont, f)` is used to generate new containers of data based on source container and
// conversion function. You have to specify the output container as template argument. There
// are also `map_f_to_a` instances, which returns std::array - avoids the need to specify
// the return container in template.
//
// This is useful for situations like: for each item in dataset calculate X and store it in
// a new container.
auto mapped_vec = em::map_f<std::vector<int>>(vec_data, [](int val) {
return -val;
});
for (int v : mapped_vec) {
std::cout << "mapped val: " << v << '\n';
}
std::array<std::string, 11> mapped_arr = em::map_f_to_a<11>(vec_data, [](auto item) {
return std::to_string(item);
});
for (const std::string &s : mapped_arr) {
std::cout << "mapped arr val: " << s << '\n';
}
// ---------------------------------------------------------------------------------------
// as a shortcut for `map_f` functions, we have `convert_to<T>` and it's `T operator(U)`
// which simply constructs T from inserted types.
struct foo_conv {
int i;
};
auto mapped_struct_vec =
em::map_f<std::vector<foo_conv>>(vec_data, em::convert_to<foo_conv>{});
for (foo_conv v : mapped_struct_vec) {
std::cout << "mapped float val: " << v.i << '\n';
}
// ---------------------------------------------------------------------------------------
// `joined` is used for example to join strings with an delimiter
std::vector<std::string> string_data{"a", "b", "c", "d", "e"};
std::cout << "joined string data: " << em::joined(string_data, std::string{","}) << '\n';
}
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment