I am storing values in a std::map
I am finding two values in the map, and I want to iterate between the first through to the last item - however the <= operator is not implemented, so I can't do somethimng like this:
void foobar(const DatedRecordset& recs, const double startstamp, const double endtstamp)
{
DatedRecordsetConstIter start_iter = recs.lower_bound(startstamp), end_iter = recs.lower_bound(endtstamp);
// Can't do this .... (<= not defined)
//for (DatedRecordsetConstIter cit = start_iter; cit <= end_iter; cit++ )
/ So have to resort to a hack like this:
for (DatedRecordsetConstIter cit = start_iter; cit != recs.end(); cit++ ) {
if ((*cit).first <= (*end_iter).first){
//do something;
}
else
break;
}
}
}
Is there a more elegant way of iterating between two known iterators?
Use != instead of <= and it will do what you want it to do.
void foobar(const DatedRecordset& recs, const double startstamp, const double endtstamp)
{
DatedRecordsetConstIter start_iter = recs.lower_bound(startstamp),
end_iter = recs.upper_bound(endtstamp);
for (DatedRecordsetConstIter cit = start_iter; cit != end_iter; ++cit) {
}
}
There isn't a <= operator for std::map<>::iterator, but using != on end_iter should do basically the same thing. If you want to include the end iterator itself in the iteration, use something like a do loop to do the != test at the end.
struct ManipulateMatchingPairs {
template<class K, class V>
void operator()(const std::pair<K,V>& p) const {
// do with p.second as you please here.
}
};
// ...
std::for_each(start_iter, end_iter, ManipulateMatchingPairs());
You have to use the != operator. I believe this is because a std::map isn't necessarily contiguous in memory (so the <= operator wouldn't make much sense, whereas a std::vector would), I could be wrong though
The STL for_each algorithm also will not include the ending iterator in the loop. You could always increcment end_iter and just use for_each so that it will be included, though.
void foobar(const DatedRecordset& recs,
const double startstamp,
const double endtstamp)
{
DatedRecordsetConstIter start_iter = recs.lower_bound(startstamp);
DatedRecordsetConstIter end_iter = recs.lower_bound(endtstamp);
if(end_iter != recs.end())
++end_iter;
for_each(start_iter, end_iter, []()
{
//do something inside the lambda.
});
}
Something like that maybe? I didn't give it a compile check ...
If you want to include the end iterator in the loop, you can increment your end-condition iterator ++end_iter. After that the loop with cit != end_iter does the same as you intend to do with cit <= end_iter before incrementing.
Related
Given std::set , what is the best way to change the set during time-iteration?
For example:
std::set<T> s; // T is a some type (it's not important for the question).
// insertions to s
for (std::set<T>::iterator it = s.begin(); it != s.end(); it++) {
T saveIt(*it);
s.erase(*it);
s.insert( saveIt + saveIt ); // operator+ that defined at `T`
}
According to what that I read in some sources, it's bad way because that: the removing from the set may change the structure of the set.
So what is the better (/best) way to do it?
Your loop may result in almost endless loop because you keep adding larger elements at the back of your set. Until T + T overflows.
Correct way is to create a new set:
std::set<T> s;
std::set<T> s2;
for(auto const& elem : s)
s2.insert(elem + elem);
s.swap(s2);
With boost::range it is a one-liner:
#include <boost/range/adaptor/transformed.hpp>
// ...
std::set<int> s;
s = boost::copy_range<std::set<int>>(s | boost::adaptors::transformed([](int x) { return x + x; }));
Just have a copy std:set
std::set<T> s;
std::set<T> modified_s;
for (std::set<T>::iterator it = s.begin(); it != s.end(); it++) {
modified_s.insert(*it+ *it);
}
s = std::move(modified_s);
Edit:
Added std::move as improvement from #Jodocus
I'm trying to write a program where given a vector, you use iterators to compare the first and last number of the vector, then moves in and compares the next ones. I wrote the for loop to do that, but am unsure how to make it stop once they reach the center of the vector.
For the for loop I have:
for (a = v.begin(), b = v.rbegin(); a != v.end(), b != v.rend(); a++, b++)
where a is the forward iterator and b is a backwards iterator.
My assumption is that I need to change the condition of the for loop, but I'm unsure to what.
So bear in mind that std::vector<T>::iterator is a random-access iterator, which means that it has operator< defined.
Using this, and using the std::reverse_iterator<Iterator>::base() member function, we can rewrite your for-loop to the following:
auto a = v.begin();
auto b = v.rbegin();
for (; a < b.base(); ++a, ++b)
{
// Do stuff...
}
First of all you need to use && and not the , operator in the comparison, which doesn't do what you think it does.
For your specific question you just keep going until both iterators reach each other, you can obtain the underlying std::iterator of a std::reverse_iterator through base(), eg:
template<typename T> bool isPalindrome(const std::vector<T>& data)
{
for (auto it = data.begin(), it2 = data.rbegin(); it != data.end() && it2 != data.rend() &&
it != it2.base(); ++it, ++it2)
if (*it != *it2)
return false;
return true;
}
I have a container<std::deque<T>> and a const T*ptr which I know points to an object in one of the contained deques. Now, I like to know (1) which deque it comes from and (2) its index in that one. How to get that info?
I'm aware that I can iterate over all objects, but there ought to be a faster solution, ought it not?
Something like (and I havent compiled this but you get the idea):
container<deque<T>> MyCont;
for( auto iter = MyCont.begin(); iter != MyCont.end(); ++iter )
{
auto foundIter = find( *iter.begin(), *iter.end(), MyObject );
if ( foundIter != *iter.end() )
{
dequeIndex = distance( *iter.begin(), foundIter );
containerIndex = distance( MyCont.begin(), iter );
break;
}
}
That's a task for a double iteration:
iterate over container
iterate over current element (a deque) and compare
#
template<typename container> std::pair<container::iterator_t, size_t> FindIndices(const container& c, const container::value_type* x) {
for(auto a = c.begin(); a != c.end(); a++)
for(auto b = a->begin(); b != a->end(); b++)
if(&*b == x)
return std::pair<container::iterator_t, size_t>(a, b-a->begin());
return std::pair<container::iterator_t, size_t>(c.end(), -1);
}
If you can instead store shared_pointers or unique_pointers in your container, you can use a std::map to efficiently retrieve the indices, as long as those don't change.
If only the queue does not change, then there is still some potential for savings.
I am new to C++ and I am unsure how to do this. I am trying to learn templates.
This is my current code. It sends a container (not specified which type it will receive) and returns true if the integer passes alongside the iterators is in the container. False if it does not appear.
#include <iostream>
#include <vector>
#include <list>
template <typename Iter>
bool function(Iter first, Iter last, const int x)
{
for (auto it = first; it!=last; ++it)
{
if (*it == x)
{
return true;
}
}
return false;
}
int main()
{
std::vector<int> vec = {1,2,5,10,11};
std::list<int> lis = {1,1,5,9,55};
auto first = vec.begin(), last = vec.end();
auto first2 = lis.begin(), last2 = lis.end();
std::cout<<function(first, last, 11);
std::cout<<function(first, last, 9)<<std::endl;
std::cout<<function(first2, last2, 6);
std::cout<<function(first2, last2, 55)<<std::endl;
return 0;
}
I would like to modify this function so that instead of returning a bool, it returns an iterator to the first match. How would I go about doing this? It would be really helpful if someone could push me in the right direction.
I don't really know how to push you in the right direction without just giving you the answer, since it is so simple.
template <typename Iter>
Iter // change 1
function(Iter first, Iter last, const int x)
{
for (auto it = first; it!=last; ++it)
{
if (*it == x)
{
return it; // change 2
}
}
return last; // change 3
}
By the way, this is exactly what std::find does.
I have a class with an standard container member, and I'm wondering is that possible that I make an own iterator with a specific route, for example it goes back and forth, and after that stops.
template<class T>
class compressed_string {
vector<T> v;
public:
typedef typename std::vector<T>::iterator iterator;
iterator begin() { return v.begin(); }
iterator end() { return v.end(); }
compressed_string& add(const T& elem) {
v.push_back(elem);
return *this;
}
basic_string<T> not_nice_way_to_make_real_string() {
basic_string<T> tmp;
for(iterator i = v.begin(); i < v.end(); ++i)
tmp += *i;
for(iterator i = --v.end(); i >= v.begin(); --i)
tmp += *i;
return tmp;
}
};
main:
compressed_string<char> s;
s.add('q').add('w').add('e').add('w');
cout << s.not_nice_way_to_make_real_string(); // q w e w w e w q
cout << endl
for ( compressed_string<char>::iterator i = s.begin(); i < s.end(); ++i )
cout << *i;
So with this iterator member the output would be the same in this two lines.
How is this possible?
You'll need an iterator that stores a bit of state:
where it is (e.g. an iterator v_it over v)
where it's going (e.g. bool forward)
where it's bounded (e.g. iterators v_begin = v.begin() and v_end = v.end())
and some otherwise invalid iterator to represent the end, such as {v_end, backward}).
Then implement the increment operator along the lines of:
if (forward) {
if (++v_it == v_end) {
forward = false;
--v_it;
}
} else {
if (v_it-- == v_begin) {
v_it = v_end;
}
}
and similarly for decrement, if you want a bidirectional iterator; in which case, it would be polite to provide a reverse_iterator too. You should provide both pre- and post-increment forms.
You'll also need == and != comparisons, comparing both v_it and forward, and dereference operators * and -> that dereference v_it, and suitable begin and end functions; for bonus points, a const_iterator would be nice.
Note that you'll need random access if you really want the code in your question (i < s.end() rather than the more generic i != s.end()) to work; that's entirely possible, but rather excessive if you don't otherwise need it.
UPDATE: as noted in the comments, this particular implementation could probably be improved a bit; for example, it's possible to remove the need to store v_begin if you're a bit careful about how you define the end iterator.