I have this simple code:
std::vector<std::map<double,double>> v;
//populate v
//we know each map already has correct key order (enforced by c++)
//but i also want to make sure the different maps have correct key order
//this is how I do it using a pointer:
const double *last_key = nullptr;
for (const auto &map : v)
{
if (map.size() > 0) //ignore empty maps
{
if (last_key)
{
const auto &new_key = map.cbegin()->first;
if (!(*last_key < new_key))
throw std::runtime_error("invalid key order");
}
last_key = &(--map.cend())->first;
}
}
Is this a good use for pointers? How would you do it instead?
The only real alternative I know (if I want to avoid pointers) is to do this:
double last_key;
bool last_key_has_been_set = false;
This works, but it requires that the key is default constructible and it involves unnecessary copying of keys (problem for different key types than double).
OK, since I now (think I) understand what your code is about, here's my take on it:
auto iter = v.begin();
auto end = v.end();
while (iter != end && iter->empty())
++iter;
if (iter != end)
{
while (true) // loop and a half
{
auto next = iter+1; // at this point, we know iter != end
while (next != end && next->empty())
++next;
if (next == end)
break;
auto lhslast = lhs.end();
--lhslast;
if (lhslast->first > next->begin()->first)
throw std::runtime_error("invalid key order");
iter = next;
}
}
Edit:
The code above can be further improved using another algorithm:
Replace
while (iter != end && iter->empty())
++iter;
with
iter = std::find_if(iter, end,
[](std::map<double, double> const& m) { return m.empty(); });
and analogous for the next loop.
Another option is to notice that if it were not empty maps, you could just use adjacent_find. Therefore another option is to make use of Boost's filter_iterator to get rid of the empty maps. Thus do
#include <boost/iterator/filter_iterator.hpp>
struct is_not_empty
{
template<typename Container> bool operator()(Container const& c) const
{
return !c.empty();
}
};
and then at the place of your code
auto fbegin = boost::make_filter_iterator(is_not_empty(), v.begin(), v.end());
auto fend = boost::make_filter_iterator(is_not_empty(), v.end(), v.end());
if (std::adjacent_find(fbegin, fend,
[](std::map<double, double> const& lhs,
std::map<double, double> const& rhs) -> bool
{
auto lhslast = lhs.end();
--lhslast;
return lhslast->first > rhs.begin()->first;
}) != fend)
throw std::runtime_error("invalid key order");
The filter iterator makes sure that only the non-empty maps are considered.
I don't think there is a suitable predefined algorithm in the standard library that does this. In particular, std::adjacent_find could be used for this if you were to define a relatively complex and stateful predicate for it, but that would really amount to misusing std::adjacent_find as some kind of replacement for std::for_each, i.e. it would not have much to do with the original purpose of std::adjacent_find.
However, instead of naked pointers, you should be using iterators. I'd also suggest putting the checking code into a separate function, perhaps named check. Here is what I would suggest:
#include <vector>
#include <map>
#include <iostream>
bool check(const std::vector<std::map<double,double>> &v)
{
/* Fast-forward to the first non-empty entry. */
auto it = begin(v);
for( ; it != end(v) ; ++it)
if (!it->empty())
break;
/* We might be done by now. */
if (it == end(v))
return true;
/* Else, go through the remaining entries,
skipping empty maps. */
auto prev = it->end();
advance(prev,-1);
++it;
for ( ; it != end(v) ; ++it)
{
if (!it->empty())
{
if (it->begin()->first < prev->first)
return false;
prev = it->end();
advance(prev,-1);
}
}
return true;
}
int main()
{
std::vector<std::map<double,double>> v;
/* Two entries for the vector, invalid order. */
v.push_back({ {1.0,1.0} , {2.0,4.0} });
v.push_back({ {3.0,9.0} , {1.0,16.0} });
if (!check(v))
throw std::runtime_error("Invalid order of the maps in the vector.");
return 0;
}
Note: It would be even more C++-like (or, at least more like the algorithms in the standard library) if you were to define the check function as an algorithm that takes a range of iterators, rather than a reference to a container, as argument. Rewriting the function to match this concept is straight-forward.
Note 2: The advantage of using iterators instead of naked pointers is that you get a better and cleaner abstraction of what you need: Something that references an item in the map, whereas a double* pointer could be pointing to all kinds of things. However, there is also a disadvantage of using iterators: If you were to modify your algorithm such that it alters maps while iterating through the vector, the iterator may be invalidated, whereas the pointer would not (unless you delete the element it points to). (The pointers might be invalidated if you alter the vector, though.)
But as long as the checking procedure is only used for checking and nothing else (which my code indicates by putting the code into a separate function dedicated to this purpose, and by taking the vector as a const-reference), iterator invalidation is not an issue.
This uses a C++1y feature (std::tr2::optional), but should work with any container and any ordering on the elements of the containers:
struct compare_key_order {
template<typename LHS, typename RHS>
bool operator()( LHS const& lhs, RHS const& rhs ) {
return lhs.first < rhs.first;
}
};
template<typename ContainerOfContainers, typename Ordering>
bool are_container_endpoints_ordered( ContainerOfMaps&& meta, Ordering&& order=compare_key_order() )
{
using std::begin; using std::end;
// or boost::optional:
std::tr2::optional< decltype( begin(begin(meta)) ) > last_valid;
for( auto&& Map : std::forward<Meta>(meta) ) {
auto b = begin(Map);
auto e = end(Map);
if (b==e)
continue;
if (last_valid)
if (!order( **last_valid, *b ))
return false;
last_valid = e;
}
return true;
}
optional is a prettier, less error prone way of dealing with the "this element may or may not exist" than a pointer-that-can-be-nullptr. If you are using boost or have access to a std::tr2::optional (or you are reading this in the future, when std::optional exists), it is a better idea than a pointer.
You could also move the "is there a last_valid out of state and into program code location:
struct compare_key_order {
template<typename LHS, typename RHS>
bool operator()( LHS const& lhs, RHS const& rhs ) {
return lhs.first < rhs.first;
}
};
template<typename ContainerOfContainers, typename Ordering>
bool are_container_endpoints_ordered( ContainerOfMaps&& meta, Ordering&& order=compare_key_order() )
{
using std::begin; using std::end;
auto it = begin(meta);
while( it != end(meta) && (begin(*it) == end(*it)) {
++it;
}
if ( it == end(meta) )
return true;
auto last_valid_end = end(*it);
for( ++it; it != end(meta); ++it ) {
auto b = begin(*it);
auto e = end(*it);
if (b==e)
continue;
if (!order( *last_valid_end, *b ))
return false;
last_valid = e;
}
return true;
}
this would let the same algorithm run on vectors-of-vectors-of-pairs, or even check if vectors-of-vectors have sorted endpoints (with a different order).
Best noted comment gives the answer : use adjacent_find.
First a little bit of logic. If there is n < m indexes verifying key[n] > key[m], then an index i exists, n <= i < m where key[i] > key[i+i].
You can demonstrate this with absurdity reasoning : If there is no such i, then for all i between n and m we have order, and because order relation is transitive, key[n] <= key[m] : absurd.
This means, ignoring the empty maps, if you have bad order on your keys, then you have two adjacent keys in bad order.
So your algorithm shoud be:
typedef map<double, double> map_t;
vector<map_t> v;
remove_if(v.begin(), v.end(), [](map_t const& m){return m.empty();});
if(adjacent_find(v.begin(), v.end(), [](map_t const& l, map_t const& r)
{
return (--l.cend())->first > r.cbegin()->first;
}) != v.end())
throw std::runtime_error("invalid key order");
This is, of course, if you can remove the empty maps from your vector first. (we can assume that, as empty maps may not be so meaningful, but it depends on the whole situation, for sure).
Related
I have a collection of object of type "T" that i want to iterate through. An object of type "T" has two important properties:
int r; // row number
int c; // column number
I would like to define an iterator that allows me to iterate through all elements of the collection.
This can be done using:
std::vector<T> v;
for(std::vector<T>::iterator it = v.begin(); it != v.end(); ++it) {
....
}
However, I would like the iterator to have one more property. I would like to be able to call
it.nextrow()
calling this function should return the element "e" of v where e.r + 1 = ec.r and e.c = ec.c, where ec is the current element pointed by the iterator. I.e. calling it.nextrow() should give me a pointer to the element where column is the same, but row is incremented by one. Hope it makes sense.
I am not sure what I need to do in order for this to work, as I am fairly new to advanced c++ concepts. Can anybody help me?
Not everything has to be a member function. Would you accept a iterator nextRow(iterator current, iterator begin, iterator end) free function?
template<typename Iterator>
Iterator nextRow(Iterator needle, Iterator begin, Iterator end)
{
return std::find_if(begin, end, [needle](const T & elem) { return (elem.r == needle->r + 1) && (elem.c == needle->c); });
}
If your vector is always sorted, you don't need a separate begin, just use needle.
If you do need this to be a part of a wrapper iterator, that type will need to contain a begin and end.
template <typename Iterator>
class SearchableIterator
{
Iterator wrapped, begin, end;
public:
difference_type Iterator::difference_type;
value_type Iterator::value_type;
pointer Iterator::pointer;
reference Iterator::reference
iterator_category Iterator::iterator_category
SearchableIterator(Iterator wrapped, Iterator begin, Iterator end)
: wrapped(wrapped), begin(begin), end(end) {}
// All the members, calling that member of wrapped (see std::reverse_iterator for guidance)
SearchableIterator nextRow()
{
return SearchableIterator(std::find_if(begin, end, [this](const T & elem) { return (elem.r == wrapped->r + 1) && (elem.c == wrapped->c); }), begin, end);
}
}
Iterators are copyable.
You can
derive from the container's iterator for your container,
add construction from the container's iterator,
add your extra property members,
and declare that begin(), end(), etc from your custom container return your derived iterator.
Assuming your data are packed in a vector with consecutive items for all columns of a row followed by items of the next row, you would just need *(iterator + column_count) to access the next-row-same-column value (don't try this on an iterator that's already pointing into the last row of data)
You can create a wrapper iterator similar to Implement custom iterator for c++ std container and give it a specific column count as additional information:
template<typename T, int colsize, typename TIterator = std::vector<T>::iterator>
class MyRowIterator : public std::iterator<std::forward_iterator_tag, T>
{
private:
TIterator m_pter;
public:
MyRowIterator(TIterator& value): m_pter(value)
{
}
MyRowIterator(const MyRowIterator& other_it): m_pter(other_it.m_pter)
{
}
MyRowIterator& operator++()
{
++m_pter;
return *this;
}
bool operator!=(const MyRowIterator& rhs)
{
return m_pter != rhs.m_pter;
}
T& operator*()
{
return (*m_pter);
}
// here it is
T& nextrow()
{
return *(m_pter+colsize);
}
};
Usage example:
void Test()
{
std::vector<int> data;
// 2 rows each 10 columns
data.resize(20);
for (auto& item : data)
{
item = 0;
}
data[2] = 1;
data[12] = 5;
// don't iterate the last line, else nextrow() will access out of bounds!
for (MyRowIterator<int, 10> iter = data.begin(); iter != (data.end()-10); iter++)
{
std::cout << *iter << " # " << iter.nextrow() << std::endl;
}
}
Suppose I have a vector named spot_deals of SpotDeal that is a class:
class SpotDeal
{
public:
int deal_id_; // primary key, and vector is sorted by id
string ccy_pair_; // ccy pair, e.g. GBPUSD, AUDUSD
double amount_;
}
Say I need to pass two subset of spot_deals to a function foo for some computation. I could make copies, however, that would cost memory and time. Actually foo only needs iterators of deals. So can I make 2 iterators of vector<SpotDeal>, namely it1 and it2 and pass them to foo?
The two subset of spot_deals could be filtered by ccy_pair_, e.g. deals of GBPUSD and AUDUSD, or by other conditions. So I'm looking for a way to define an iterator defined by a vector and a lambda function (could equivalently be a functor though).
Is there a way to write a helper function make_filtered_iterator so that I can have something like below?
auto it1 = make_filtered_iterator(spot_deals, filter_lambda1);
auto it2 = make_filtered_iterator(spot_deals, filter_lambda2);
foo(it1, it2);
The answer is certainly "yes." C++ iterators in the STL style can be made to do all sorts of tricks. A common but basic one is making an iterator for std::map which when dereferenced gives only the key or the value.
In your particular case, a simple implementation might be like this:
template <typename BaseIterator>
struct filtered_iterator : BaseIterator
{
typedef std::function<bool (const value_type&)> filter_type;
filtered_iterator() = default;
filtered_iterator(filter_type filter, BaseIterator base, BaseIterator end = {})
: BaseIterator(base), _end(end), _filter(filter_type) {
while (*this != _end && !_filter(**this)) {
++*this;
}
}
filtered_iterator& operator++() {
do {
BaseIterator::operator++();
} while (*this != _end && !_filter(**this));
}
filtered_iterator operator++(int) {
filtered_iterator copy = *this;
++*this;
return copy;
}
private:
BaseIterator _end;
filter_type _filter;
};
template <typename BaseIterator>
filtered_iterator<BaseIterator> make_filtered_iterator(
typename filtered_iterator<BaseIterator>::filter_type filter,
BaseIterator base, BaseIterator end = {}) {
return {filter, base, end};
}
I set a default value for end because typically you can use a default-constructed iterator for that. But in some cases you might want to filter only a subset of the container, in which case specifying the end makes it easy.
Yes, it would be possible to create an iterator type. However, I suspect your question is an example of an XY problem (https://meta.stackexchange.com/questions/66377/what-is-the-xy-problem) - you want to find a way to operate differently on two subsets of a vector (X), have decided the solution must involve implementing a special-purpose iterator (Y), and have asked how to do Y rather than X. I am going to provide an option to do X without needing to do Y.
I suggest it would be easier to use standard algorithm std::stable_partition() to separate the container into two ranges.
auto false_partition = std::stable_partition(your_vector.begin(), your_vector.end(), your_filter);
The begin() and end() iterators of the vector do not change (i.e. are not invalidated), but the elements between them are reorganised into two ranges, such that the elements for which your_filter returns true precedes the set of elements for which your_filter returns false. false_partition is therefore simultaneously the "past the end" iterator for the first range, and the beginning of the second range. The order of elements in each range is the same as in the original vector.
These can be used as follows
// a loop to operates on the elements for which your_filter returned true
for (auto i = your_vector.begin(); i != false_partition; ++i)
{
// do whatever
}
// a loop to operates on the elements for which your_filter returned false
for (auto i = false_partition; i != your_vector.end(); ++i)
{
// do whatever
}
Before C++11, the auto keyword can be replaced with appropriate iterator types (e.g. std::vector<int>::iterator or std::vector<int>::const_iterator, depending on whether you want the elements to be changed using the iterators).
I may suggest viewers of this question get a crash course with Eric Nibbler's rangev3 because that's the paradigm adopted for C++20 standard lib.
https://github.com/ericniebler/range-v3
How to do your filter iteration:
for (auto element : spot_deals | views::filter([](auto i) { return condition(i); }))
{ //....
}
I wouldn't use iterators pointing to your original vector, because they cannot convey the size of your subsets. (Basically, you would need one more iterator per subset to represent the end of the subsets.) As of C++20, I would work with ranges from the Ranges library, as mentioned in v.oddou's answer. More specifically, for your use case, I would use the range adaptor std::views::filter as follows:
auto gbpusd = [](const auto& sd) { return sd.ccy_pair_ == "GBPUSD"; };
auto audusd = [](const auto& sd) { return sd.ccy_pair_ == "AUDUSD"; };
auto range1 = spot_deals | std::views::filter(gbpusd);
auto range2 = spot_deals | std::views::filter(audusd);
foo(range1, range2);
This solution does not create temporary vectors for the filtered spot deals, because the view adaptors create ranges that don't contain elements. The resulting ranges range1 and range2 are just views over the vector spot_deals, but with customized iteration behaviors.
The declaration of foo() is a bit tricky, because the data types of the ranges are quite complex. I would therefore use the placeholder type auto for the function parameters and thus make foo() a function template:
void foo(auto& r1, auto& r2) {
for (auto const& sd : r1)
std::cout << sd.deal_id_ << std::endl;
for (auto const& sd : r2)
std::cout << sd.amount_ << std::endl;
}
(Alternatively, you could pass spot_deals by reference to foo() and declare the filtered ranges inside foo().)
Code on Wandbox
By chance, I've recently worked on this exact problem. As it turns out, filtering is the most complicated of quite some operations on a container, and also contains the most pitfalls.
template<typename Range, typename Pred>
class filter
{
public:
friend class const_iterator;
class const_iterator : public std::iterator_traits<typename Range::const_iterator>
{
using underlying = typename Range::const_iterator;
public:
auto operator*() {return *u;}
const_iterator& operator++()
{
++u;
normalize();
return *this;
}
const_iterator operator++(int)
{
auto t = *this;
u++;
normalize();
return t;
}
bool operator==(const const_iterator& rhs) const {return u == rhs.u;}
bool operator!=(const const_iterator& rhs) const {return !(*this == rhs);}
private:
friend filter;
const_iterator(underlying u, const filter& f) : u{std::move(u)}, f{f} {normalize();}
void normalize()
{
for(; u != f.r.end() && !f.p(*u); u++);
}
underlying u;
const filter& f;
};
filter(const Range& r, const Pred& p) : r{r}, p{p} {}
auto begin() const {return const_iterator{r.begin(), *this};}
auto end() const {return const_iterator{r.end(), *this};}
private:
const Range& r;
Pred p;
};
We use it as (with c++17 guide)
vector<int> v{1, 2, 3, 4, 5};
auto f = filter(v, [](int x){return x & 1;});
for(auto i : f)
// all i in v that is odd
Let me explain the pitfalls:
The first element might be filtered out, *r.begin() might not be an element in the filtered range. This means the iterator has to be checked on construction.
r.end() might be invalidated without invalidating other iterators, that is to say, saving a copy of r.end() in any iterators to compare with is a logic error.
operator== is not very straightforward, two underlying iterators referring to different elements in the original range might be referring to the same element in the filtered view because filtered out elements doesn't count as an element.
Here is the task came to me from a code review. I want to select a minimum value from a set, based on a special kind of compare predicate. Like this:
struct Complex { ... };
float calcReduction(Complex elem);
Complex findMinValueWithPredicates(const std::vector<Complex>& values)
{
auto it = std::min_element(values.begin(), values.end(),
[](const Complex& a, const Complex& b) {
return calcReduction(a) < calcReduction(b);
});
if (it == values.end()) throw std::runtime_error("");
return *it;
}
Here I find the minimum element based on a predicate. This predicate computes a reduction of both values to float and then compares those floats. Works fine, looks neat.
Can you see the problem? Yes, for a set of N elements calcReduction() is called 2N times, while it is enough to compute it only N times - once for each element.
One way to solve this problem is to write explicit computations:
Complex findMinValueExplicit(const std::vector<Complex>& values)
{
float minReduction = std::numeric_limits<float>::max();
Complex minValue;
for (Complex value : values)
{
float reduction = calcReduction(value);
if (reduction < minReduction)
{
minReduction = reduction;
minValue = value;
}
}
if (minReduction == std::numeric_limits<float>::max()) throw std::runtime_error("");
return minValue;
}
It works fine and we only have N calls to calcReduction(). However, it looks too verbose and the intent is not such clear, as compared to explicit call of min_element. Because when you call min_element it is really easy to guess you are going to find a minimum element, you know.
The only idea I have for now is to create my own algorithm like min_element_with_reduction, accepting a range and a reduction function. Sounds reasonable, but I wonder whether there are any ready solutions.
Any ideas on how to solve this task with clear intent and some ready solutions? Boost is welcomed. C++17 and ranges are interesting to see.
You could use boost::range library.
auto reductionLambda = [](const Complex& a) { return calcReduction(a); };
auto it = boost::range::min_element(values | boost::adaptors::transformed(
std::ref(reductionLambda));
Ranges themselves should be coming to the standard C++ with C++17 as well.
Edit
As we figured out in comments, this would also make the conversion twice.
So here's something fun:
#include <boost/iterator/iterator_adaptor.hpp>
#include <boost/assign.hpp>
#include <algorithm>
#include <iostream>
#include <vector>
#include <functional>
template <class Iterator, class UnaryFunction>
class memoizing_transform_iterator
: public boost::iterator_adaptor<
memoizing_transform_iterator<Iterator, UnaryFunction> // Derived
, Iterator // Base
, std::decay_t<decltype(std::declval<UnaryFunction>()(std::declval<typename Iterator::value_type>()))> // Value
, boost::forward_traversal_tag // CategoryOrTraversal
>
{
public:
memoizing_transform_iterator() {}
explicit memoizing_transform_iterator(Iterator iter, UnaryFunction f)
: memoizing_transform_iterator::iterator_adaptor_(iter), fun(f) {}
static int total;
private:
friend class boost::iterator_core_access;
void increment() { ++this->base_reference(); memoized = false; }
using MemoType = std::decay_t<decltype(std::declval<UnaryFunction>()(std::declval<typename Iterator::value_type>()))>;
MemoType& dereference() const
{
if (!memoized) {
++total;
memoized = true;
memo = fun(*this->base());
}
return memo;
}
UnaryFunction fun;
mutable bool memoized = false;
mutable MemoType memo;
};
template <class Iterator, class UnaryFunction>
auto make_memoizing_transform_iterator(Iterator i, UnaryFunction&& f)
{
return memoizing_transform_iterator<Iterator, UnaryFunction>(i, f);
}
template<class I, class U>
int memoizing_transform_iterator<I, U>::total = 0;
// THIS IS COPIED FROM LIBSTDC++
template<typename _ForwardIterator>
_ForwardIterator
min_el(_ForwardIterator __first, _ForwardIterator __last)
{
if (__first == __last)
return __first;
_ForwardIterator __result = __first;
while (++__first != __last)
if (*__first < *__result)
__result = __first;
return __result;
}
int main(int argc, const char* argv[])
{
using namespace boost::assign;
std::vector<int> input;
input += 2,3,4,1,5,6,7,8,9,10;
auto transformLambda = [](const int& a) { return a*2; };
auto begin_it = make_memoizing_transform_iterator(input.begin(), std::ref(transformLambda));
auto end_it = make_memoizing_transform_iterator(input.end(), std::ref(transformLambda));
std::cout << *min_el(begin_it, end_it).base() << "\n";
std::cout <<begin_it.total;
return 0;
}
Basically I implemented an iterator that memoizes the result of calling the transformation functor. The weird part though is that at least in online compilers, the iterators are copied before their dereferenced values are compared (thus defeating the purpose of memoizing). However when I simply copied the implementation from libstdc++, it works as expected. Perhaps you could try it out on a real machine? The live example is here.
Small edit:
I tested on VS2015 and it works as expected with std::min_element.
Here's a solution using (already works with the range-v3 library, the implementation by the author of the upcoming Ranges TS)
#include <range/v3/all.hpp>
#include <iostream>
#include <limits>
using namespace ranges::v3;
int main()
{
auto const expensive = [](auto x) { static int n; std::cout << n++ << " "; return x; };
auto const v = view::closed_iota(1,10) | view::transform(expensive);
auto const m1 = *min_element(v);
std::cout << "\n" << m1 << "\n";
auto const inf = std::numeric_limits<int>::max();
auto const min = [](auto x, auto y) { return std::min(x, y); };
auto const m2 = accumulate(v, inf, min);
std::cout << "\n" << m2 << "\n";
}
Live On Coliru with output:
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
1
19 20 21 22 23 24 25 26 27 28
1
As you can see, using min_element takes 2N comparisons, but using accumulate only N.
The only thing missing is the meta-iterator.
A meta-iterator takes an iterator, and creates an iterator that contains a copy of it. It passes all operations through to the contained iterator, except when dereferenced returns a copy of the contained iterator instead.
With any care, the code used for this also works to create an iterator over size_t or int or similar torsor-likes.
template<class It, class R>
struct reduced_t {
It it;
R r;
friend bool operator<( reduced_t const& lhs, reduced_t const& rhs ) {
return lhs.r < rhs.r;
}
};
template<class It, class F>
reduced_t<It, std::result_of_t<F(typename std::iterator_traits<It>::reference)>>
reducer( It it, F&& f ) {
return {it, std::forward<F>(f)(*it)};
}
template<class It, class F>
It reduce( It begin, It end, F&& f ) {
if (begin==end)
return begin;
return std::accumulate(
meta_iterator(std::next(begin)), meta_iterator(end),
reducer(begin, f),
[&](
auto&& reduced, // reduced_t<blah...> in C++11
It i
) {
auto r2 = reducer( i, f );
return (std::min)(reduced, r2);
}
).it;
};
f(*it) is called exactly once per iterator.
I wouldn't call this ... obvious. The trick is that we use accumulate and meta-iterators to implement min_element, then we can have accumulate operate on transformed elements (which gets called once, and returned).
You could rewrite it in stack-based programming style using primitives, but there are lots of primitives to write. Maybe post ranges-v3.
At this point, I'm imagining having some high-powered compositional programming library. If I did, we could do the following:
reducer( X, f ) can be rewritten graph( deref |then| f )(X) using order_by( get_n_t<1> ) for ordering.
The accumulate call could read accumulate( skip_first(range), g(begin(range)), get_least( order_by( get_n_t<1> ) ) ).
Not sure if that is any clearer.
If you take a minElem as a lambda parameter you could use min_element
Complex findMinValueWithPredicates(const std::vector<Complex>& values)
{
float minElem = std::numeric_limits<float>::max();
auto it = std::min_element(values.begin(), values.end(),
[&minElem](const Complex& a, const Complex& b) {
float tmp = calcReduction(a);
if (tmp < minElem) {
minElem = tmp;
return true;
}
return false;
});
if (it == values.end()) throw std::runtime_error("");
return *it;
}
Edit:
Why does this work when bis not used?
25.4.7.21 min_element
21 Returns: The first iterator i in the range [first,last) such that
for every iterator j in the range [first,last) the following
corresponding conditions hold: !(*j < *i) or comp(*j, *i) == false.
Returns last if first == last.
because b should have been named smallestYet (code from cplusplus.com)
template <class ForwardIterator>
ForwardIterator min_element ( ForwardIterator first, ForwardIterator last )
{
if (first==last) return last;
ForwardIterator smallest = first;
while (++first!=last)
if (*first<*smallest) // or: if (comp(*first,*smallest)) for version (2)
smallest=first;
return smallest;
}
Which lead me to a new favourite quote:
"There are only 10 hard problems in Computer Science:
cache invalidation, naming things and off-by-one errors."
one commented on that we might be off-by-one as we don't use b.
I worried that the minElem cached might not be correct.
And I realized that the name b should have been more meaningful as it is "dereferenced iterator to smallest element yet" or smallestYet.
Finally that not all understand binary when its not written with a ´b´ at the end.
Here is another option, but it is still effectively your second solution. To be honest it doesn't look clear, but someone might like it. (I use std::pair<float, Complex> to store reduction result and the value that was reduced.)
std::pair<float, Complex> result{std::numeric_limits<float>::max(), {}};
auto output_function = [&result](std::pair<float, Complex> candidate) {
if (candidate.first < result.first)
result = candidate;
};
std::transform(values.begin(), values.end(),
boost::make_function_output_iterator(output_function),
[](Complex x) { return std::make_pair(calcReduction(x), x); });
P.S. If your calcReduction costs a lot, have you considered caching results in Complex objects? It will lead to a slightly more complicated implementation, but you'll be able to use plain std::min_element which makes your intentions clear.
Can you suggest a nicer way of inserting a value before another value in an std::vector:
template<class T>
void insert(std::vector<T>& container, const T& valueToInsertBefore, const T& valueToInsert)
{
std::vector<T>::iterator i = container.begin();
std::vector<T>::iterator end = container.end();
for(;i!=end;++i)
{
if(*i==valueToInsertBefore)
{
i = container.insert(i, valueToInsert);
i++;
end = container.end();
}
}
}
UPDATE:
Should insert for each instance of valueToInsertBefore found in the std::vector.
Use std::find() to locate the value instead of the explicit loop:
std::vector<T>::iterator i = v.begin();
while (v.end() != (i = std::find(i, v.end(), valueToInsertBefore)))
{
// insert() returns an iterator to the inserted element.
// The '+ 2' moves past it and the searched for element.
//
i = v.insert(i, valueToInsert) + 2;
}
std::vector may turn out to be rather inefficient due to the needed reallocations in case it's rather large and/or the element to be inserted before appears very often. A more simplistic approach using a copy like this might turn out to be more CPU-friendly (at the expense of requiring more memory):
template<class T>
void insert(std::vector<T>& container,
const T& valueToInsertBefore,
const T& valueToInsert)
{
std::vector<T> result;
result.reserve( container.size() );
std::vector<T>::const_iterator it, end = container.end();
for ( it = container.begin(); it != end; ++it ) {
if ( *it == valueToInsertBefore ) {
result.push_back( valueToInsert );
}
result.push_back( *it );
}
container.swap( result );
}
container.insert(std::find(container.begin(), container.end(), valueToInsertBefore), valueToInsert);
You better change container, lists are better for this kind of operations. With an insert you are risking to invalidate iterators and pointers and you also need memory reallocations.
http://www.cplusplus.com/reference/stl/vector/insert/
I am trying to write a binary function that takes two vectors(of the same length) and adds them by value. For some reason the following code does not work:
struct Plusval : binary_function <std::vector<int>,std::vector<int>,std::vector<int> >
{
std::vector<int> operator() (const std::vector<int>& x, const std::vector<int>& y) const
{
std::vector<int> ret(x);
std::vector<int>::iterator itx,ity;
ity=y.begin();
for (itx=ret.begin();itx<ret.end();++itx)
{
ret[*itx]+=y[*ity];
++ity;
}
return ret;
}
};
I get an error that I can't do ity=y.begin()
However, the following code does work
struct Plusval : binary_function <std::vector<int>,std::vector<int>,std::vector<int> >
{
std::vector<int> operator() (const std::vector<int>& x, const std::vector<int>& y) const
{
std::vector<int> ret(x);
std::vector<int> yloc(y);
std::vector<int>::iterator itx,ity;
ity=yloc.begin();
for (itx=ret.begin();itx<ret.end();++itx)
{
ret[*itx]+=yloc[*ity];
++ity;
}
return ret;
}
};
Obviously, the second version will take longer (since it has to copy an additional vector). Is it because the input is a const vector? If it is, is there any reason it needs to be? Note that I am planning on using this function as an input to the allreduce() function in boost::mpi if that makes any difference
You define ity as vector::iterator y is const and returns a const_iterator.
What is more important is: Don't use binary_function. The adapters have been deprecated.
Also, your function does not do what you want. *itx returns the value stored at the position pointed to by itx and you use it to index into the you intend to return vector.
I would write this with a binary transform.
std::vector<int> res;
std::transform(begin(x), end(x), begin(y),
std::back_inserter(res), std::plus<int>());
The error is that you cannot use non-const iterators with a const container, as that would break const-correctness. You should use std::vector<int>::const_iterator on the second argument.
Other than that, the implementation in the first block does not do what you claim it does.You are iterating over the container and using the stored values to index into the container and update there. If you actually want to add the values from the two containers, it is much simpler than that:
struct PlusVal
{
std::vector<int> operator()( std::vector<int> lhs, std::vector<int> const& rhs )
{
assert( lhs.size() == rhs.size() );
for (std::vector<int>::size_type i = 0; i < lhs.size; ++i )
lhs[i] += rhs[i];
return lhs;
}
};
If you want to do that with iterators, it is again similarly simple:
struct PlusVal
{
std::vector<int> operator()( std::vector<int> lhs, std::vector<int> const& rhs )
{
assert( lhs.size() == rhs.size() );
std::vector<int>::iterator it = lhs.begin(), end = lhs.end();
std::vector<int>::const_iterator rit = rhs.begin();
while ( it != end )
*it++ += *rit++;
return lhs;
}
};
You're looking for the std::vector::const_iterator type
std::vector<int> operator() (const std::vector<int>& x, const std::vector<int>& y)
{
std::vector<int> result;
// Not strictly necessary, but helps with performance a bit
result.reserve(std::min(x.length(), y.length());
for (std::vector<int>::const_iterator x_it = x.begin(),
y_it = y.begin();
x_it != x.end() && y_it != y.end();
++x_it, ++y_it)
{
result.push_back(*x_it + *y_it);
}
return result;
}
It looks like you've already gotten a reasonable answer or two; I'll just point out an alternative. Though I hesitate to mention it, std::valarray fits so well for this I just can't resist:
std::valarray<int> x;
std::valarray<int> y;
// code to populate x and y elided
x += y;
Ever few months (or so) I see something valarray would make so simple I find it truly regrettable that it's been lost and forgotten (then I think about things like slice, gslice, slice_array, indirect_array, etc., and wish I hadn't thought of it at all).