The header <algorithm> contains a version of std::transform() taking a two input sequences, an output sequence, and a binary function as parameters, e.g.:
#include <algorithm>
#include <iostream>
#include <iterator>
#include <vector>
int main()
{
std::vector<int> v0{1, 2, 3};
std::vector<int> v1{4, 5, 6};
std::vector<int> result;
std::transform(v0.begin(), v0.end(), v1.begin(), std::back_inserter(result),
[](auto a, auto b){ return a + b; });
std::copy(result.begin(), result.end(),
std::ostream_iterator<int>(std::cout, " "));
std::cout << '\n';
}
C++20 introduced range algoirthms which does include std::ranges::views::transform(R, F) and its implementation std::ranges::views::transform_view. I can see how to use this transform() with one range, e.g.:
#include <algorithm>
#include <iostream>
#include <iterator>
#include <ranges>
#include <vector>
int main()
{
std::vector<int> v0{1, 2, 3};
for (auto x: std::ranges::views::transform(v0, [](auto a){ return a + 3; })) {
std::cout << x << ' ';
}
std::cout << '\n';
}
However, there is no version supporting more than one range. So, the question becomes: How to use the range version of transform() with two (or more) ranges? On objective of this approach is to benefit from the lazy evaluation of views and avoid the creation of an intermediate sequence (result in the non-ranges version above). A potential use could look like this (putting the function argument in front to make it easier for a potential solution allowing even more than two ranges):
for (auto v: envisioned::transform([](auto a, auto b){ return a + b; }, v0, v1) {
std::cout << v << ' ';
}
std::cout << '\n';
The way you would like to use transform, where you take an arbitrary number of input ranges is not possible directly with what's available in <algorithm> as of C++20. You can of course write such an algorithm yourself without too much effort.
The example with 2 input ranges can be implemented in C++20 like this:
std::ranges::transform(v0, v1,
std::ostream_iterator<int>(std::cout, " "),
std::plus{});
Here's a demo, and this is specifically the last overload of transform listed here.
There is unfortunately no way to write the equivalent version like this:
for (auto v : std::views::transform(v0, v1, std::plus{})) // no, unfortunately
std::cout << v << " ";
but the above implementation does the same thing. It certainly satisfies your requirements of not having to store the results separately; they can be printed as they're generated.
What you're looking for is the algorithm that range-v3 calls zip_with and what we are proposing in P2214 to add to C++23 under the name zip_transform. There is no such algorithm in C++20.
Until then, the range-v3 version is exactly your use-case:
for (auto v : zip_with([](auto a, auto b){ return a + b; }, v0, v1)) {
std::cout << v << ' ';
}
It can handle an arbitrary number of ranges.
Note that there is no piping version here, just as there is not with regular zip.
The answer blow is how I envisioned to answer the question and I think it still contains some interesting bits on how to actually implement a view. It turns out that P2214 mentioned in #Barry's answer has an interesting view (zip_transform) which does an intermediate step of the solution posted below but actually fully covers the functionality needed to do a multi-range transform!
It seems there are essentially two ingredients to using std::ranges::views::transform() with multiple ranges:
Some way to zip the objects at the corresponding positions of the ranges into a std::tuple, probably retaining the value category of the respective values.
Instead of using an n-ary function to take the elements of the range as parameters the function would rather use a std::tuple and possibly use that to call a corresponding n-ary function.
Using this idea would allow creating a version of transform() dealing with an arbitrary number of ranges, although it is easier to take the function object first rather than extract the last element of a parameter pack:
auto transform(auto&& fun, auto&&... ranges)
{
return std::ranges::views::transform(zip(std::forward<decltype(ranges)>(ranges)...),
[fun = std::forward<decltype(fun)>(fun)]
(auto&& t){ return std::apply(fun, std::forward<decltype(t)>(t)); });
}
The zip view used by this implementation can be implemented in terms of std::tuple:
template <typename... Range>
struct zip_view
: std::ranges::view_base
{
template <typename V>
struct rvalue_view
{
std::shared_ptr<std::decay_t<V>> view;
rvalue_view() = default;
rvalue_view(V v): view(new std::decay_t<V>(std::move(v))) {}
auto begin() const { return this->view->begin(); }
auto end() const { return this->view->end(); }
};
template <typename T>
using element_t = std::conditional_t<
std::is_rvalue_reference_v<T>,
rvalue_view<T>,
T
>;
using storage_t = std::tuple<element_t<Range>...>;
using value_type = std::tuple<std::ranges::range_reference_t<std::remove_reference_t<Range>>...>;
using reference = value_type;
using difference_type = std::common_type_t<std::ranges::range_difference_t<Range>...>;
storage_t ranges;
template <typename> struct base;
template <std::size_t... I>
struct base<std::integer_sequence<std::size_t, I...>>
{
using value_type = zip_view::value_type;
using reference = zip_view::value_type;
using pointer = value_type*;
using difference_type = std::common_type_t<std::ranges::range_difference_t<Range>...>;
using iterator_category = std::common_type_t<std::random_access_iterator_tag,
typename std::iterator_traits<std::ranges::iterator_t<Range>>::iterator_category...>;
using iterators_t = std::tuple<std::ranges::iterator_t<Range>...>;
iterators_t iters;
reference operator*() const { return {*std::get<I>(iters)...}; }
reference operator[](difference_type n) const { return {std::get<I>(iters)[n]...}; }
void increment() { (++std::get<I>(iters), ...); }
void decrement() { (--std::get<I>(iters), ...); }
bool equals(base const& other) const {
return ((std::get<I>(iters) == std::get<I>(other.iters)) || ...);
}
void advance(difference_type n){ ((std::get<I>(iters) += n), ...); }
base(): iters() {}
base(const storage_t& s, auto f): iters(f(std::get<I>(s))...) {}
};
struct iterator
: base<std::make_index_sequence<sizeof...(Range)>>
{
using base<std::make_index_sequence<sizeof...(Range)>>::base;
iterator& operator++() { this->increment(); return *this; }
iterator operator++(int) { auto rc(*this); operator++(); return rc; }
iterator& operator--() { this->decrement(); return *this; }
iterator operator--(int) { auto rc(*this); operator--(); return rc; }
iterator& operator+= (difference_type n) { this->advance(n); return *this; }
iterator& operator-= (difference_type n) { this->advance(-n); return *this; }
bool operator== (iterator const& other) const { return this->equals(other); }
auto operator<=> (iterator const& other) const {
return std::get<0>(this->iters) <=> std::get<0>(other.iters);
}
friend iterator operator+ (iterator it, difference_type n) { return it += n; }
friend iterator operator+ (difference_type n, iterator it) { return it += n; }
friend iterator operator- (iterator it, difference_type n) { return it -= n; }
friend difference_type operator- (iterator it0, iterator it1) {
return std::get<0>(it0.iters) - std::get<0>(it1.iters);
}
};
zip_view(): ranges() {}
template <typename... R>
zip_view(R&&... ranges): ranges(std::forward<R>(ranges)...) {}
iterator begin() const { return iterator(ranges, [](auto& r){ return std::ranges::begin(r); }); }
iterator end() const { return iterator(ranges, [](auto& r){ return std::ranges::end(r); }); }
};
auto zip(auto&&... ranges)
-> zip_view<decltype(ranges)...>
{
return {std::forward<decltype(ranges)>(ranges)...};
}
This implementation makes some decisions about the value_type and the reference type and how to keep track of the different ranges. Other choices may be more reasonable (P2214 makes slightly different, probably better, choices). The only tricky bit in this implementation is operating on the std::tuples which requires a parameter pack containing indices or a suitable set of algorithms on std::tuples.
With all of that in place a multi-range transform can be used nicely, e.g.:
#include <algorithm>
#include <iostream>
#include <iterator>
#include <memory>
#include <ranges>
#include <utility>
#include <tuple>
#include <type_traits>
#include <vector>
// zip_view, zip, and transform as above
int main()
{
std::vector<int> v0{1, 2, 3};
std::vector<int> v1{4, 5, 6};
std::vector<int> v2{7, 8, 9};
for (auto x: transform([](auto a, auto b, auto c){ return a + b + c; }, v0, v1, v2)) {
std::cout << x << ' ';
}
std::cout << '\n';
}
Related
Using the following containers:
std::vector<std::pair<std::string, int>> keyVals = {
{"A", 1}, {"B", 2}, {"C", 3}
};
std::vector<std::string> keys = {
"A", "B", "C"
};
I need to construct a sorted output container
std::set<std::tuple<std::string, int, int>>
using the std::set_intersection between keyVals and keys.
These types use a common field (in my case a string) this is also used for pre-sorting these vectors via the default std::less - however no need in the above example as they are already sorted.
I need help to create a sorted container C that is not just a simple copy of elements from A to the output over the intersection range.
Instead I need to be able to construct each output element C - in my case a std::tuple<std::string, int, int> (where the first entry in the tuple is the common link string field and the other 2 int are some global fields.
To illustrate the problem I created a coliru live demo where I commented out the broken code - I don't know how to invoke a custom constructor for each iteration - please help.
#include <vector>
#include <variant>
#include <memory>
#include <iostream>
#include <algorithm>
// Helper to get Lambda with multiple signatures in place
// template deduction guide is a C++17 feature!
template<class... Ts> struct overload : Ts... { using Ts::operator()...; };
// this line is necessary for c++17 - not required for c++20
template<class... Ts> overload(Ts...) -> overload<Ts...>;
template<typename T>
std::ostream& operator<<(std::ostream& os, const std::vector<T>& vec) {
for (auto& el : vec) {
os << el.first << ' ';
}
return os;
}
// if c++17 is not available, you have to write a functor/function
// with both signatures
int main()
{
std::vector<std::pair<std::string, int>> keyVals = {
{"A", 1}, {"B", 2}, {"C", 3}
};
std::vector<std::string> keys = {
"A", "B", "C"
};
// std::set_intersection results can only be of the first iterator type
std::vector<std::pair<std::string, int>> intersection;
// this works
std::set_intersection(
keyVals.begin(), keyVals.end(),
keys.begin(), keys.end(),
std::back_inserter(intersection),
overload {
[](const std::pair<std::string, int>& lhs, const std::string& rhs) {
return lhs.first < rhs;
},
[](const std::string& lhs, const std::pair<std::string, int>& rhs) {
return lhs < rhs.first;
}
}
);
std::cout << intersection << std::endl;
#if 0
// std::set_intersection results can only be of the first iterator type
std::vector<std::tuple<std::string, int, int>> broken_intersection;
// this does not work as no match for 'operator=' *__result = *__first1;
std::set_intersection(
keyVals.begin(), keyVals.end(),
keys.begin(), keys.end(),
std::back_inserter(broken_intersection), // help here - I need to be able to
overload {
[](const std::pair<std::string, int>& lhs, const std::string& rhs) {
return lhs.first < rhs;
},
[](const std::string& lhs, const std::pair<std::string, int>& rhs) {
return lhs < rhs.first;
}
}
);
std::cout << broken_intersection << std::endl;
#endif
}
The problem is, as already noted, the different types of the data.
All input and output containers habe a different type.
And with that, 2 main operations in std::set_difference need to be expressed.
The comparison of the dereferenced input iterators of different type
The assignment of a rvalue from the dereferenced input to the dereferenced output iterator.
Problem 1 can be easily solved with a Functor, for which we will create 2 function call operators with the 2 needed signatures. This will allow for comparison in both directions.
Starting with C++14 you may also use a generic Lambda:
auto cmp = [](auto lhs, auto rhs) { return lhs.mCommonField < rhs.mCommonField; };
But then you need some common fields in both vectors.
The same approach would be possible with a Functor having a templated call operator:
struct Comparator
{
template<typename T, typename U>
bool operator()(T const& lhs, U const& rhs) const {
return lhs.commonField < rhs.commonField;
}
};
Also here you need a common field. And they must have the same name. Maybe this will not fit here.
Or, we could create a wrapper for a Common Field:
struct Common {
std::string const& commonField;
Common(StructA const& sa) : commonField{sa.commonField} {};
Common(StructB const& sb) : commonField{sb.commonField} {};
};
Here the common field must just be of the same type.
Many possibilities
For problem 2 we need a small wrapper. Either for the first input iterator or the output iterator. The wrapper needs to have iterator functionality and a dereferencing operator that returns a Tuple, so that we can assign this Tuple to the resulting vector of Tuples.
So we will create a very small custom iterator, with only the minimumm functions needed by std::set_intersection
Construction
Dereferencing
Pre Incrementing
Comparison for not equal
Within the iterator we will use a simple pointer to a Pair as the real iterator. The constructor can get a pointer to the Pairs in the first vector with the std::vector data function. That is very convenient.
The dereferencing operator does the trick. It will not return a Pair, but construct a Tuple and return that. So, this is the conversion from the Pair to a Tuple.
Putting this altogether may lead to one of many potential solutions:
#include <string>
#include <vector>
#include <iostream>
#include <algorithm>
#include <tuple>
#include <utility>
using Key = std::string;
using Value = int;
using Keys = std::vector<Key>;
using Pair = std::pair<Key, Value>;
using KeyVals = std::vector<Pair>;
using Tuple = std::tuple<Key, Value, Value>;
using Tuples = std::vector<Tuple>;
std::ostream& operator<<(std::ostream& os, const Tuples& t) {
for (auto& el : t) os << std::get<0>(el) << ' ';
return os;
}
struct Iterator {
using iterator_category = std::output_iterator_tag;
using difference_type = std::ptrdiff_t;
using value_type = Tuple;
using pointer = Tuple*;
using reference = Tuple&;
Pair* iter; // The internal iterator. Just a pointer
Iterator(Pair* kv) { iter = kv; }
Tuple operator *() const { return Tuple{ iter->first,0,0}; }
Iterator operator ++() { ++iter; return *this; }
bool operator !=(const Iterator& other) { return iter != other.iter; }
};
struct Comp {
bool operator ()(const Tuple& lhs, const std::string& rhs) { return std::get<0>(lhs) < rhs; }
bool operator ()(const std::string& lhs, const Tuple& rhs) { return lhs < std::get<0>(rhs) ; }
};
int main()
{
KeyVals keyVals = { {"A", 1}, {"B", 2}, {"C", 3} };
Keys keys = { "A", "B", "C" };
// Resulting vector
Tuples tupleResult{};
// Create Iterators to KeyVals
Iterator begin(keyVals.data());
Iterator end(keyVals.data() + keyVals.size());
// Do the intersection
std::set_intersection(begin, end, keys.begin(), keys.end(), std::back_inserter(tupleResult), Comp());
// Show result
std::cout << tupleResult << '\n';
}
Looks a little bit clumsy
On a 2nd thought, you could convert both input vectors to the needed output type using std::transform. But this will cost additional space and time.
Anyway, please see the next potential solution:
#include <iostream>
#include <vector>
#include <string>
#include <algorithm>
#include <iterator>
#include <utility>
#include <tuple>
using Key = std::string;
using Value = int;
using Keys = std::vector<Key>;
using Pair = std::pair<Key, Value>;
using KeyVals = std::vector<Pair>;
using Tuple = std::tuple<Key, Value, Value>;
using Tuples = std::vector<Tuple>;
std::ostream& operator<<(std::ostream& os, const Tuples& t) {
for (auto& el : t) os << std::get<0>(el) << ' ';
return os;
}
int main()
{
KeyVals keyVals = { {"A", 1}, {"B", 2}, {"C", 3} };
Keys keys = { "A", "B", "C" };
// Convert to same type
Tuples tupleKeyVals{}, tupleKeys{};
std::transform(keyVals.begin(), keyVals.end(), std::back_inserter(tupleKeyVals), [](const Pair& p) { return Tuple{ p.first, p.second, 0 }; });
std::transform(keys.begin(), keys.end(), std::back_inserter(tupleKeys), [](const std::string& s) { return Tuple{ s, 0, 0 }; });
// Resulting vector
Tuples tupleResult{};
// Build intersection based on first tuple element
std::set_intersection(tupleKeyVals.begin(), tupleKeyVals.end(), tupleKeys.begin(), tupleKeys.end(), std::back_inserter(tupleResult),
[](const Tuple& t1, const Tuple& t2) { return std::get<0>(t1) < std::get<0>(t2); });
std::cout << tupleResult << '\n';
}
This looks a little bit cleaner. But disadvantage is much more memory consumption and longer operation time.
Last but not least, we could implement an own set_intersetcion function, which is quite simple.
#include <iostream>
#include <vector>
#include <string>
#include <algorithm>
#include <iterator>
#include <utility>
#include <tuple>
using Key = std::string;
using Value = int;
using Keys = std::vector<Key>;
using Pair = std::pair<Key, Value>;
using KeyVals = std::vector<Pair>;
using Tuple = std::tuple<Key, Value, Value>;
using Tuples = std::vector<Tuple>;
std::ostream& operator<<(std::ostream& os, const Tuples& t) {
for (auto& el : t) os << std::get<0>(el) << ' ';
return os;
}
// Specialized intersection function
Tuples set_intersection(KeyVals& kv, Keys& k) {
Tuples result{};
KeyVals::iterator iterKeyVal = kv.begin();
Keys::iterator iterKey = k.begin();
while (iterKeyVal != kv.end() and iterKey != k.end()) {
if (iterKeyVal->first < *iterKey)
++iterKeyVal;
else {
if (not(*iterKey < iterKeyVal->first))
result.emplace_back(Tuple{ (iterKeyVal++)->first ,0,0 });
++iterKey;
}
}
return result;
}
int main()
{
// Input
KeyVals keyVals = { {"A", 1}, {"B", 2}, {"C", 3} };
Keys keys = { "A", "B", "C" };
// Resulting vector
Tuples tupleResult = set_intersection(keyVals, keys);
// Show result
std::cout << tupleResult << '\n';
}
But in the end you need to decide based on other requirements or constraints.
How can I wrap an OutputIterator such as back_inserter_iterator with a transformation?
Consider
std::vector<double> xx;
std::vector<double> yy;
std::vector<double> diff;
auto ba = std::back_inserter(diff);
std::set_difference(xx.begin(), xx.end(), yy.begin(), yy.end(), ba);
I would like to apply a free function f(double) or g(std::vector<double>::iterator) before pushing back to the diff vector:
Specifically, how can I store the addresses of the diff elements (or iterators) instead of the elements themeselves.
std::vector<double&> diff;
auto baAdr = ??? std::back_inserter( ??? (diff));
std::set_difference(xx.begin(), xx.end(), yy.begin(), yy.end(), baAdr);
For performance reasons (the real data is big) I do not want to construct a temporary vector and std::transform from it. It would also not work for non-copyable, movable types.
I can use boost.
With boost::function_output_iterator:
#include <vector>
#include <algorithm>
#include <boost/function_output_iterator.hpp>
int main()
{
std::vector<double> xx;
std::vector<double> yy;
std::vector<const double*> diff; // const pointers, or else you
// need a const_cast in lambda
std::set_difference(xx.begin(), xx.end(), yy.begin(), yy.end(),
boost::make_function_output_iterator(
[&diff](const double& d) { diff.push_back(&d); }
)
);
}
There's probably something built in to boost, but here's my hacky attempt to write my own iterator:
template <typename T, typename FN>
struct transform_iterator {
transform_iterator(T &t, FN fn)
: _t{t}
, _fn{std::move(fn)} { }
transform_iterator<T, FN>& operator * () { return *this; }
transform_iterator<T, FN>& operator ++ () { return *this; }
template <typename V>
transform_iterator<T, FN>& operator = (V const &v) {
_t.push_back(_fn(v));
return *this;
}
T &_t;
FN _fn;
};
This will take a function and execute it whenever something tries to assign to the iterator (I think this is how things like back_inserter usually work). A trivial helper function can create the iterators:
template <typename T, typename FN>
auto make_transform_iterator(T &t, FN fn) {
return transform_iterator<T, FN>{t, std::move(fn)};
};
Lastly, iterator_traits needs to be specialized so transform_iterator will work with algorithms.
namespace std {
template <typename T, typename FN>
struct iterator_traits<transform_iterator<T, FN>> {
using value_type = typename T::value_type;
};
}
There are more types that need to be set in iterator_traits, but this was sufficient for my testing; your mileage will vary.
My main looks like this:
int main() {
std::vector<int> xx{1, 2, 3};
std::vector<int> yy{1, 3, 5};
std::vector<int> diff;
auto ba = make_transform_iterator(diff, [](auto v) { return v + 10; });
std::set_difference(std::begin(xx), std::end(xx),
std::begin(yy), std::end(yy),
ba);
for(auto const &v: diff) {
std::cout << v << '\n';
}
return 0;
}
You could expand this to work with generic output iterators instead of just types that support push_back.
Is there a nice implementation of the algorithm to calculate the convolution of two ranges in C++ STL (or even boost)?
i.e. something with prototype (convolution of two ranges a..b and c..d):
template< class Iterator >
void convolution(Iterator a, Iterator b, Iterator c, Iterator d);
which modifies a..b range
Yes std::transform
std::transform(a, b, c, a, Op);
// a b is the the first input range
// c is the start of the second range (which must be at least as large as (b-a)
//
// We then use a as the output iterator as well.
// Op is a BinaryFunction
To answer the comment on how to perform accumulation of state in the comments:
struct Operator
{
State& state;
Operator(Sate& state) : state(state) {}
Type operator()(TypeR1 const& r1Value, TypeR2 const& r2Value) const
{
Plop(state, r1Value, r2Value);
return Convolute(state, r2Value, r2Value);
}
};
State theState = 0;
Operator Op(theState);
I'm not quite sure what a "convolution" from two sequences to one of these two sequences is supposed to be: It seems to be a different understanding than my understanding. Below is a version of convolution using a variable number of iterators. Because I'm actually just too lazy for now, I'll use a somewhat uncommon notion of passing the destination iterator as first argument rather than as last argument. Here is an implementation of a corresponding zip() algorithms:
#include <tuple>
namespace algo
{
template <typename... T>
void dummy(T...)
{
}
template <typename To, typename InIt, typename... It>
To zip(To to, InIt it, InIt end, It... its)
{
for (; it != end; ++it, ++to) {
*to = std::make_tuple(*it, *its...);
algo::dummy(++its...);
}
return to;
}
}
Below is a simple test program I used to verify that the above does what I intended it to do:
#include <deque>
#include <iostream>
#include <iterator>
#include <list>
#include <vector>
enum class e { a = 'a', b = 'b', c = 'c' };
std::ostream& operator<< (std::ostream& out,
std::tuple<int, double, e> const& v)
{
return out << "["
<< std::get<0>(v) << ", "
<< std::get<1>(v) << ", "
<< char(std::get<2>(v)) << "]";
}
int main()
{
typedef std::tuple<int, double, e> tuple;
std::vector<int> v{ 1, 2, 3 };
std::deque<double> d{ 1.1, 2.2, 3.3 };
std::list<e> l{ e::a, e::b, e::c };
std::vector<tuple> r;
algo::zip(std::back_inserter(r), v.begin(), v.end(), d.begin(), l.begin());
std::copy(r.begin(), r.end(),
std::ostream_iterator<tuple>(std::cout, "\n"));
}
I have trouble describing my problem so I'll give an example:
I have a class description that has a couple of variables in it, for example:
class A{
float a, b, c, d;
}
Now, I maintain a vector<A> that contains many of these classes. What I need to do very very often is to find the object inside this vector that satisfies that one of it's parameters is maximal w.r.t to the others. i.e code looks something like:
int maxi=-1;
float maxa=-1000;
for(int i=0;i<vec.size();i++){
res= vec[i].a;
if(res > maxa) {
maxa= res;
maxi=i;
}
}
return vec[maxi];
However, sometimes I need to find class with maximal a, sometimes with maximal b, sometimes the class with maximal 0.8*a + 0.2*b, sometimes I want a maximal a*VAR + b, where VAR is some variable that is assigned in front, etc. In other words, I need to evaluate an expression for every class, and take the max. I find myself copy-pasting this everywhere, and only changing the single line that defines res.
Is there some nice way to avoid this insanity in C++? What's the neatest way to handle this?
Thank you!
I know this thread is old, but i find it quite useful to implement a powerful argmax function in C++.
However, as far as i can see, all the given examples above rely on std::max_element, which does comparison between the elements (either using a functor or by calling the operator<). this can be slow, if the calculation for each element is expensive. It works well for sorting numbers and handling simple classes, but what if the functor is much more complex? Maybe calculating a heuristic value of a chess position or something else that generate a huge tree etc.
A real argmax, as the thread starter mentioned, would only calculate its arg once, then save it to be compared with the others.
EDIT: Ok i got annoyed and had too much free time, so i created one < C++11 and one C++11 version with r-value references, first the C++11 version:
#include <iostream>
#include <algorithm>
#include <iterator>
#include <vector>
template<typename IteratorT, typename HeuristicFunctorT>
IteratorT argmax(IteratorT && it, const IteratorT & end, const HeuristicFunctorT & functor) {
IteratorT best(it++);
typename HeuristicFunctorT::result_type best_value(functor(*best));
for(; it != end; ++it) {
typename HeuristicFunctorT::result_type value(functor(*it));
if (value > best_value) {
best_value = value;
best = it;
}
}
return best;
}
template<typename IteratorT, typename HeuristicFunctorT>
inline IteratorT argmax(const IteratorT & begin, const IteratorT & end, const HeuristicFunctorT & functor) {
return argmax(IteratorT(begin), end, functor);
}
class IntPairFunctor : public std::unary_function< std::pair<int, int>, int > {
public:
int operator() (const std::pair<int, int> & v) const {
return v.first + v.second;
}
};
std::pair<int, int> rand_pair() {
return std::make_pair(rand(), rand());
}
int main(int argc, const char **argv) {
srand(time(NULL));
std::vector< std::pair<int, int> > ints;
std::generate_n(std::back_insert_iterator< std::vector< std::pair<int, int> > >(ints), 1000, rand_pair);
std::vector< std::pair<int, int> >::iterator m (argmax(ints.begin(), ints.end(), IntPairFunctor()));
std::cout << std::endl << "argmax: " << *m << std::endl;
}
The non C++11 version is much simpler, only the template:
template<typename IteratorT, typename HeuristicFunctorT>
IteratorT argmax(IteratorT it, const IteratorT & end, const HeuristicFunctorT & functor) {
IteratorT best(it++);
typename HeuristicFunctorT::result_type best_value(functor(*best));
for(; it != end; ++it) {
typename HeuristicFunctorT::result_type value(functor(*it));
if (value > best_value) {
best_value = value;
best = it;
}
}
return best;
}
Note that neither version requires any template arguments, the only requirement is that the heuristic implements the unary_function class
template <typename F>
struct CompareBy
{
bool operator()(const typename F::argument_type& x,
const typename F::argument_type& y)
{ return f(x) < f(y); }
CompareBy(const F& f) : f(f) {}
private:
F f;
};
template <typename T, typename U>
struct Member : std::unary_function<U, T>
{
Member(T U::*ptr) : ptr(ptr) {}
const T& operator()(const U& x) { return x.*ptr; }
private:
T U::*ptr;
};
template <typename F>
CompareBy<F> by(const F& f) { return CompareBy<F>(f); }
template <typename T, typename U>
Member<T, U> mem_ptr(T U::*ptr) { return Member<T, U>(ptr); }
You need to include <functional> for this to work. Now use, from header <algorithm>
std::max_element(v.begin(), v.end(), by(mem_ptr(&A::a)));
or
double combination(A x) { return 0.2 * x.a + 0.8 * x.b; }
and
std::max_element(v.begin(), v.end(), by(std::fun_ptr(combination)));
or even
struct combination : std::unary_function<A, double>
{
combination(double x, double y) : x(x), y(y) {}
double operator()(const A& u) { return x * u.a + y * u.b; }
private:
double x, y;
};
with
std::max_element(v.begin(), v.end(), by(combination(0.2, 0.8)));
to compare by a member or by linear combinations of a and b members. I split the comparer in two because the mem_ptr thing is damn useful and worth being reused. The return value of std::max_element is an iterator to the maximum value. You can dereference it to get the max element, or you can use std::distance(v.begin(), i) to find the corresponding index (include <iterator> first).
See http://codepad.org/XQTx0vql for the complete code.
This is what functors and STL are made for:
// A class whose objects perform custom comparisons
class my_comparator
{
public:
explicit my_comparator(float c1, float c2) : c1(c1), c2(c2) {}
// std::max_element calls this on pairs of elements
bool operator() (const A &x, const A &y) const
{
return (x.a*c1 + x.b*c2) < (y.a*c1 + y.b*c2);
}
private:
const float c1, c2;
};
// Returns the "max" element in vec
*std::max_element(vec.begin(), vec.end(), my_comparator(0.8,0.2));
Is the expression always linear? You could pass in an array of four coefficients. If you need to support arbitrary expressions, you'll need a functor, but if it's just an affine combination of the four fields then there's no need for all that complexity.
You can use the std::max_element algorithm with a custom comparator.
It's easy to write the comparator if your compiler supports lambda expressions.
If it doesn't, you can write a custom comparator functor. For the simple case of just comparing a single member, you can write a generic "member comparator" function object, which would look something like this:
template <typename MemberPointer>
struct member_comparator
{
MemberPointer p_;
member_comparator(MemberPointer p) : p_(p) { }
template <typename T>
bool operator()(const T& lhs, const T& rhs) const
{
return lhs.*p_ < rhs.*p_;
}
};
template <typename MemberPointer>
member_comparator<MemberPointer> make_member_comparator(MemberPointer p)
{
return member_comparator<MemberPointer>(p);
}
used as:
// returns an iterator to the element that has the maximum 'd' member:
std::max_element(v.begin(), v.end(), make_member_comparator(&A::d));
You could use the std::max_element STL algorithm providing a custom comparison predicate each time.
With C++0x you can even use a lambda function for it for maximum conciseness:
auto maxElement=*std::max_element(vector.begin(), vector.end(), [](const A& Left, const A& Right) {
return (0.8*Left.a + 0.2*Left.b)<(0.8*Right.a + 0.2*Right.b);
});
Sample of using max_element/min_element with custom functor
#include <algorithm>
#include <iostream>
#include <vector>
using namespace std;
struct A{
float a, b, c, d;
};
struct CompareA {
bool operator()(A const & Left, A const & Right) const {
return Left.a < Right.a;
}
};
int main() {
vector<A> vec;
vec.resize(3);
vec[0].a = 1;
vec[1].a = 2;
vec[2].a = 1.5;
vector<A>::iterator it = std::max_element(vec.begin(), vec.end(), CompareA());
cout << "Largest A: " << it->a << endl;
it = std::min_element(vec.begin(), vec.end(), CompareA());
cout << "Smallest A: " << it->a << endl;
}
Is there an stl way to get a list of values from a map?
i.e, I have:
std::map<A,B> myMap;
and I would like a function that will return just the list of values, i.e, std::list<B> (or set for that matter.
Is there a built-in stl way to do this?
A map element is defined as a map::value_type, and the type of it is a pair<A,B>. first is the key and second is the value. You can write a functor to extract second from a value_type, and copy that in to a vector (or a list, or whatever you want.) The best way to do the copying is to use transform, which does just what its name implies: it takes a value of one type and transforms it to a different type of value.
Here's a complete working example:
#include <cstdlib>
#include <map>
#include <string>
#include <algorithm>
#include <iterator>
#include <vector>
#include <iostream>
using namespace std;
typedef map<unsigned, string> MyMap;
MyMap my_map;
struct get_second : public std::unary_function<MyMap::value_type, string>
{
string operator()(const MyMap::value_type& value) const
{
return value.second;
}
};
int main()
{
my_map[1] = "one";
my_map[2] = "two";
my_map[3] = "three";
my_map[4] = "four";
my_map[5] = "five";
// get a vector of values
vector<string> my_vals;
transform(my_map.begin(), my_map.end(), back_inserter(my_vals), get_second() );
// dump the list
copy( my_vals.begin(), my_vals.end(), ostream_iterator<string>(cout, "\n"));
}
EDIT:
If you have a compiler that supports C++0x lambdas, you can eliminate the functor entirely. This is very useful for making code more readable and, arguable, easier to maintain since you don't end up with dozens of little one-off functors floating around in your codebase. Here's how you would change the code above to use a lambda:
transform(my_map.begin(), my_map.end(), back_inserter(my_vals), [](const MyMap::value_type& val){return val.second;} );
There's nothing built in, no. It's simple enough to write your own function, though: Iterate over the map. The iterator will give you a pair<A, B>. Add each second value to the result list.
You can't just "get" such a list because there is no pre-existing list stored anywhere in the guts, but you can build one:
typedef std::map<A,B> myMapType;
myMapType myMap;
std::list<B> valueList;
for (myMapType::const_iterator it=myMap.begin(); it!=myMap.end(); ++it) {
valueList.push_back( it->second );
}
Or if you really like the more STL way:
class GetSecond {
template<typename T1, typename T2>
const T2& operator()( const std::pair<T1,T2>& key_val ) const
{ return key_val.second; }
};
typedef std::map<A,B> myMapType;
myMapType myMap;
std::list<B> valueList;
std::transform(myMap.begin(), myMap.end(), std::back_inserter(valueList),
GetSecond());
One of many "built-in" ways is of course the most obvious one. Just iterate over all pair elements, which are ordered by key (pair::first), and add the value (pair::second) to a new container, which you can construct with the correct capacity to get rid of excess allocations during the iteration and adding.
Just a note: std::list is seldom the container you actually want to be using. Unless, of course, you really, really do need its specific features.
Sure.
std::list<B> list;
std::for_each(myMap.begin(), myMap.end(), [&](const std::pair<const A, B>& ref) {
list.push_back(ref.second);
});
If you don't have a C++0x compiler, first you have my sympathies, and second, you will need to build a quick function object for this purpose.
You can use boost's transform_iterator: http://www.boost.org/doc/libs/1_64_0/libs/iterator/doc/transform_iterator.html
struct GetSecond {
template <typename K, typename T>
const T& operator()(const std::pair<K, T> & p) const { return p.second; }
template <typename K, typename T>
T& operator()(std::pair<K, T> & p) const { return p.second; }
};
template <typename MapType>
auto begin_values(MapType& m) -> decltype(boost::make_transform_iterator(m.begin(), GetSecond())) {
return boost::make_transform_iterator(m.begin(), GetSecond());
}
template <typename MapType>
auto end_values(MapType& m) -> decltype(boost::make_transform_iterator(m.end(), GetSecond())) {
return boost::make_transform_iterator(m.end(), GetSecond());
}
template <typename MapType>
struct MapValues {
MapType & m;
MapValues(MapType & m) : m(m) {}
typedef decltype(begin_values(m)) iterator;
iterator begin() { return begin_values(m); }
iterator end() { return end_values(m); }
};
template <typename MapType>
MapValues<MapType> get_values(MapType & m) {
return MapValues<MapType>(m);
}
int main() {
std::map<int, double> m;
m[0] = 1.0;
m[10] = 2.0;
for (auto& x : get_values(m)) {
std::cout << x << ',';
x += 1;
}
std::cout << std::endl;
const std::map<int, double> mm = m;
for (auto& x : get_values(mm)) {
std::cout << x << ',';
}
std::cout << std::endl;
}