-
- Downloads
lambda practice typos fixed
%% Cell type:code id:5b454048 tags: | ||
``` C++ | ||
``` c++ | ||
#include <iostream> | ||
#include <algorithm> | ||
#include <vector> | ||
#include <array> | ||
#include <cmath> | ||
#include <complex> | ||
``` | ||
%% Cell type:markdown id:9541e5f1 tags: | ||
# Practice using lambdas with algorithms | ||
%% Cell type:markdown id:eb5b5448 tags: | ||
## std::for_each | ||
%% Cell type:markdown id:4d3f33ef tags: | ||
In the following cell, we scale the elements of a vector by $1.5$ and print them. In a separate cell, use the algorithm `std::for_each` along with an appropriate lambda expression replace the values by the $sin(value)$, and | ||
show the results. | ||
%% Cell type:code id:99bbcf10 tags: | ||
``` C++ | ||
``` c++ | ||
{ | ||
std::vector X{0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 0.8, 0.7}; | ||
std::for_each(X.begin(), X.end(), [](auto& elem){ elem *= 1.5; }); | ||
std::for_each(X.begin(), X.end(), [](auto&& elem){ std::cout << elem << "\n"; }); | ||
} | ||
``` | ||
%% Cell type:code id:fd0e92e9 tags: | ||
``` C++ | ||
``` c++ | ||
``` | ||
%% Cell type:markdown id:c2172ca4 tags: | ||
## std::transform | ||
Using the slides as a guide, fill in the necessary code, so that the second sequence consists of the values $a x^2 + b x + c$, for $x$ taken from the first sequence, $a$ and $b$ being constants. | ||
%% Cell type:code id:8fb70ac5 tags: | ||
``` C++ | ||
``` c++ | ||
{ | ||
std::vector X{0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 0.8, 0.7}; | ||
std::vector<double> Y; | ||
const auto a = 2.7182818284590; | ||
const auto b = 3.1415926535897; | ||
// std::transform(what to what using what data transformation ?); | ||
} | ||
``` | ||
%% Cell type:markdown id:7f0597d6 tags: | ||
## std::copy_if | ||
Using the slides as a guild, write the necessary code to "filter" into the vector `Y` only those values out of the input vector `X`, for which the the cylindrical Bessel function of the first kind, $J_0(x) > 0.9$. Cylindrical Bessel function of the first kind $J_0(x)$ are available in the C++ standard library as `std::cyl_bessel_j(int, double)`. | ||
%% Cell type:code id:07defab8 tags: | ||
``` C++ | ||
``` c++ | ||
{ | ||
std::vector X{0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 0.8, 0.7}; | ||
std::vector<double> Y; | ||
} | ||
``` | ||
%% Cell type:markdown id:fc56123b tags: | ||
## std::partition | ||
The algorithm `std::partition` takes | ||
- the bounds of one sequence (as start and end iterators) | ||
- a unary predicate callable entity (something that can be called with one parameter, and returns true or false) | ||
and reorders the elements in the range so that all the elements which test true come before all elements which test false. The return value of the function is an iterator marking the partition point: | ||
```c++ | ||
auto p = std::partition(start, stop, criterion); | ||
``` | ||
The range `start` to `p` will then contain all elements which "pass" and `p` to `stop` will contain all elements which don't pass. Partition the range in the previous exercise using the $J_0(x)$ function and the selection criteria we used. Print the two sub ranges, along with the values of the Bessel function to show that `partition` did what is expected of it. | ||
%% Cell type:code id:164bd972 tags: | ||
``` C++ | ||
``` c++ | ||
{ | ||
std::vector X{0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 0.8, 0.7}; | ||
auto p = std::partition(X.begin(), X.end(), [](auto x){ return std::cyl_bessel_j(0, x) > 0.9; }); | ||
std::cout << "Passed...\n"; | ||
std::for_each(X.begin(), p, [](auto&& x){ std::cout << x << "\t" << std::cyl_bessel_j(0, x) << "\n"; }); | ||
std::cout << "Did not pass.\n"; | ||
std::for_each(p, X.end(), [](auto&& x){ std::cout << x << "\t" << std::cyl_bessel_j(0, x) << "\n"; }); | ||
} | ||
``` | ||
%% Cell type:markdown id:c9467bb9 tags: | ||
## std::sort | ||
Any container containing elements for which a "less than" comparison $x_i < x_j$ makes sense can be sorted. For instance, for integers, real numbers, strings etc. $a < b$ makes sense. But for complex numbers, for instance, such a comparison can not be uniquely defined. `std::sort(begin, end)` will sort any container in increasing order, so long as the elements can be compared to determine their relative ordering. Test: | ||
%% Cell type:code id:cfcc07df tags: | ||
``` C++ | ||
``` c++ | ||
{ | ||
std::vector X{1,5,3,8,9,2,7,2,6,3,1,0,8,4}; | ||
std::sort(X.begin(), X.end()); | ||
for (auto elem : X) std::cout << elem << "\n"; | ||
} | ||
``` | ||
%% Cell type:code id:fc3ffce8 tags: | ||
``` C++ | ||
``` c++ | ||
{ | ||
std::vector<std::string> X{"Conditionally", "copies", "elements", "from", "a", "source", "sequence", "to", | ||
"a", "destination", "sequence"}; | ||
// Fun exercise for those who feel adventurous: Try using CTAD in defining this vector, | ||
// and explain the results. What would you have to do to correctly use CTAD in this case ? | ||
std::sort(X.begin(), X.end()); | ||
for (auto elem : X) std::cout << elem << "\n"; | ||
} | ||
``` | ||
%% Cell type:code id:9a391f89 tags: | ||
``` C++ | ||
``` c++ | ||
{ | ||
// But this does not work. If you run this, you may have restart the kernel! | ||
std::vector<std::complex<double>> X{{1., 3.}, {0.99, 3.14}, {1.22, 0.12}}; | ||
std::sort(X.begin(), X.end(), [](auto x, auto y){ return std::abs(x) < std::abs(y); }); | ||
for (auto&& elem : X) std::cout << elem << "\n"; | ||
} | ||
``` | ||
%% Cell type:markdown id:6f7badd2 tags: | ||
However, `std::sort` can accept a callable object as another parameter, after the range parameters, which specifies how the contents of the range should be compared. It should be a function which takes two objects of the value type of the container, $x$ and $y$ (for instance), and return true if $x$ should be placed before $y$ for the current sorting operation. For instance, we can say that complex numbers should be sorted in such a way that the numbers with larger absolute value follow those with smaller absolute value. This can be expressed as $\lambda(x,y) = |x| < |y|$. Write the appropriate lambda expression as the 3rd argument to sort above and verify that you can sort by this criterion. Absolute values of complex number `c` can be calculated as `std::abs(c)`. Complex numbers are known to `std::cout`. | ||
%% Cell type:markdown id:661c8dd9 tags: | ||
How would you now sort an array of complex numbers by their real parts ? (Principle of least surprises applies here: `std::real(c)`, `std::imag(c)` ...) | ||
%% Cell type:code id:881f5069 tags: | ||
``` C++ | ||
``` c++ | ||
``` | ||
... | ... |
Please register or sign in to comment