In a for loop with auto, an iterator iterates over an unordered_map. Like this:
using RuleIndex = std::unordered_map<uint, Symbol*>;
RuleIndex rule_index;
for(const auto & rule_pair : rule_index ) {
std::cout << rule_pair.first << ": ";
printList(rule_pair.second, 0);
std::cout << std::endl;
}
Assume all variables are defined properly, since the code works fine. My question, how can I exclude the first iteration? For example, the map contains 3 rows and current loop iterates for 0, 1, 2. I want to iterate over 1 and 2 only.
bool is_first_iteration = true;
for(const auto & rule_pair : rule_index) {
if (std::exchange(is_first_iteration, false)) continue;
std::cout << rule_pair.first << ": ";
printList(rule_pair.second, 0);
std::cout << std::endl;
}
The std::exchange call assigns false to is_first_iteration and returns the previous value. This is actually one of the use cases discussed in the paper proposing std::exchange for C++14. That paper also shows a reference implementation you can use if you are stuck with C++11.
If you can't use std::exchange (due to C++11 restriction), this simple solution could work as well:
bool is_first_iteration = true;
for (const auto & rule_pair : rule_index)
{
if (is_first_iteration)
{
is_first_iteration = false;
continue;
}
std::cout << rule_pair.first << ": ";
printList(rule_pair.second, 0);
std::cout << std::endl;
}
A terse C++11 option I sometimes use, which keeps a sometimes-handy counter too. I've shown if (i++) below which relies on 0's conversion to false while other numbers convert to true, but you could put if (++i > 1) if you were more comfortable with that:
size_t i = 0;
for (const auto & rule_pair : rule_index)
if (i++)
{
...
}
...or if (++i == 1) continue;... if you prefer...
While easy to write, concise and sometimes helpful, these may be less ammenable to optimisation than a boolean version - benchmark if you care.
Yet another approach that's sometimes useful:
for (const auto & rule_pair : rule_index)
if (&rule_pair != &*std::begin(rule_index))
{
...
}
Related
is there a way how to compare each element of a vector with a constant? So far, I am comparing 2D vector Eigen::Vector2d with a constant double tolerance like this:
if (x(0) > tolerance && x(1) > tolerance)
{
...
}
I have found the function isApprox() but it did not worked somehow. Is there is a nicer or recommended way on how to do it?
One way to do this is to use the array method of the Vector class. Like this:
#include <Eigen/Dense>
#include <iostream>
int main(int argc, char * argv[]) {
Eigen::Vector2d A{ 7.5, 8.2 };
std::cout << A << '\n';
auto res = A.array() >= 8.0;
std::cout << res << '\n';
if (res.all()) {
std::cout << "True" << '\n';
}
else {
std::cout << "False" << '\n';
}
A(0) = 10.2;
auto res2 = A.array() >= 8.0;
std::cout << res2 << '\n';
if (res2.all()) {
std::cout << "True" << '\n';
}
else {
std::cout << "False" << '\n';
}
return 0;
}
In this case res and res2 are CwiseBinaryOp which contains booleans for each element in A. Use all to find when both are True.
I feel like a good call on this one is to write a simple function:
bool is_componentwise_greater_than(
Eigen::Ref<Eigen::VectorXd const> const &vector, double lower_bound) {
for (auto value : vector) {
if (value <= lower_bound)
return false;
}
return true;
}
The drawback of this way compared to the solution by #Matt is, that for more complicated use cases, using an Eigen expression can be more performant (no idea, if this applies here).
The (in my opinion huge) advantage of such an solution is, that you
can see exactly what it does from its usage.
Of course you can also pack Matts solution in an aptly named function to get this advantage. Another advantage is, that with the function I provided you know exactly what it does and never have to wonder, whether using auto with an Eigen type could bite you. I guess it won't and Matt probably knows exactly why. But I (and you?) do not and therefore wouldn't want to rely on it.
Are there versions of C++11 and C++17 Range-Based For Loop iterators that can iterate to a certain position in map?
For example, if a map has 10 key-value elements, then how can I iterate through only the first three key-value elements?
The following codes only iterate through the full range of the map.
//C++11
for(auto m: mapData){
cout << m.first << ": " << m.second << endl;
}
//C++17
for(auto [key, val]: mapData){
cout << key << ": " << val << endl;
}
You either need an external counter to make early exit, eg:
int n = 0;
for(auto&& [k, v] : map)
{
if(++n > 10) break;
std::cout << k << ": " << v << std::endl;
}
Or, if you are not afraid of copying the map, you can do:
auto copy = std::map<...>{map.begin(), std::next(map.begin(), 10)};
for(auto&& [k, v] : copy)
{
std::cout << k << ": " << v << std::endl;
}
Finally, if you can use C++20, then you can simply do this:
#include <ranges>
for(auto&& [k, v] : map | std::views::take(10))
{
std::cout << k << ": " << v << std::endl;
}
Range-based for loops are just syntactic-sugar over normal begin() and end() calls. Your request of a partial iteration are complicated by the fact that std::map does not have random-access iterators -- which incurs a cost per iterator incrementing.
To avoid redundant costs, your best option would be to us range-based for loops to a specific counter with a break:
auto count = 0;
for (const auto& [k,v] : map) {
if (++count > n) { break; }
// process 'k', 'v'
}
If you are looking for a "standard" approach, you can use std::for_each_n which lets you choose the length. You just need to ensure that the count doesn't exceed the length of container:
auto length = std::min(map.size(), n);
std::for_each_n(map.begin(), n, [&](const auto& kv) {
// process kv
});
Though the std::for_each_n approach is largely equivalent to the first approach with a counter.
If you expand to support c++20, your options open up a bit since you can construct a std::ranges::subrange:
for (const auto& [k,v] : std::ranges::subrange(map.begin(), std::advance(map.end(), n)) {
// process 'k', 'v'
}
The downside with this approach is that std::map iterators are not random-access -- which means you are paying the cost of iterating the sequence twice. For the most part, this isn't really worth it just to try to leverage range-based for loops.
Edit: See #InnocentBystander's answer with std::views::take(...) as an alternative, which will effectively produce something equivalent to the count+break-based approach.
I am following along the great book C++17 by Example, which introduces C++17 by showcasing a series of mini projects -- very cool.
However, in chapter 2, where a Set is implemented on top of a LinkedList, there is this code:
void Set::read(std::istream& inStream) {
int size;
inStream >> size;
int count = 0;
while (count < size) {
double value;
inStream >> value;
insert(value);
++count;
}
}
void Set::write(std::ostream& outStream) {
outStream << "{";
bool firstValue = true;
Iterator iterator = first();
while (iterator.hasNext()) {
outStream << (firstValue ? "" : ", ") << iterator.getValue();
firstValue = false;
iterator.next();
}
outStream << "}";
}
int main() {
Set s, t;
s.read(std::cin);
t.read(std::cin);
std::cout << std::endl << "s = ";
s.write(std::cout);
std::cout << std::endl;
std::cout << std::endl << "t = ";
t.write(std::cout);
std::cout << std::endl << std::endl;
// snip
}
I am fairly new to C++, and I do not know how to run this. Of course, I did some research before asking, but the way I came up with does not produce the expected results:
lambdarookies-MacBook:02-the-set-class lambdarookie$ ./02-the-set-class
1 2 3
3 4 5
s = {2} // Expected: s = {1, 2, 3}
t = {3, 4, 5}
Now I am wondering:
Is this simply not the right way to supply arguments, or
it is the right way, and the bug must be elsewhere in the code?
The first number Set::read reads is the size of the set. Then it reads that many numbers, and adds them to the set. The rest of the line is ignored by the current invocation of read, and is picked up by the next one, which is, by coincidence, the size of the next set you are testing with. Therefore, inputting 1 2 3 results in a set of size 1, with the only elem 2.
Please note: hasNext is a java-ism, unlike how the usual C++ iterators work. Perhaps you could consider also taking a look at a different manual.
I have tried many other similar questions but none of them helped me. My problem is as following:
I have 3 vectors of pointers to my struct: vector<state*>where state is my kind of struct. What I am trying to do is to remove states from vectorCheck if they are in either vectorOpen or vectorClosed. The point is, it sometimes works fine and sometimes not. According to CodeBlocks this seems to be a problem but I have no idea to overcome this. I debugged my program step by step and at some point, state from vectorCheck is not being removed despite of the fact it is in vectorClosed.
Iterating is held by 2 for loops:
vector<state*> vectorOpen;
vector<state*>::iterator itOpen;
vector<state*> vectorClosed;
vector<state*>::iterator itClosed;
vector<state*> vectorCheck;
vector<state*>::iterator itCheck;
for(itCheck = vectorCheck.begin(); itCheck != vectorCheck.end(); itCheck++) {
for(itOpen = vectorOpen.begin(); itOpen != vectorOpen.end(); itOpen++) {
if ((*itCheck)->player->x == (*itOpen)->player->x &&
(*itCheck)->player->y == (*itOpen)->player->y &&
(*itCheck)->box[0].x == (*itOpen)->box[0].x &&
(*itCheck)->box[0].y == (*itOpen)->box[0].y) {
cout << "erasing as in open " << (*itCheck)->player->x << " " << (*itCheck)->player->y << " " << (*itCheck)->box[0].x << " " << (*itCheck)->box[0].y << endl;
vectorCheck.erase(itCheck);
}
}
}
for(itCheck = vectorCheck.begin(); itCheck != vectorCheck.end(); itCheck++) {
for(itClosed = vectorClosed.begin(); itClosed != vectorClosed.end(); itClosed++) {
if((*itCheck)->player->x == (*itClosed)->player->x &&
(*itCheck)->player->y == (*itClosed)->player->y &&
(*itCheck)->box[0].x == (*itClosed)->box[0].x &&
(*itCheck)->box[0].y == (*itClosed)->box[0].y) {
cout << "erasing as in closed " << (*itCheck)->player->x << " " << (*itCheck)->player->y << " " << (*itCheck)->box[0].x << " " << (*itCheck)->box[0].y << endl;
vectorCheck.erase(itCheck);
}
}
}
Where vectorCheck is a maximum size of 3. To explain what I mean here is the picture
Where I am talking here about states in green rectangulars (3 1 2 4). Why isn't it being removed like the state in blue rectangular (2 2 2 4)? It should be removed as this state has appeared already in vectorClosed (code above).
What am I doing wrong? This is not the first iteration of the program, it happens in like 6th or 7th loop.
Also, this is probably causing my program to crash later on.
As mentioned in my comment, the problem is that you are continuing to use an iterator to an element you erased. std::vector::erase(i) is invalidating the itCheck iterator.
We can fix this by taking advantage of C++ algorithms like std::remove_if. It may make the code appear more complex at first glance, but you'll find this style of coding lets you reuse pieces of logic, improving the readability and maintainability of your code.
To start, let's write a functor that does the equality comparison you need.
struct states_are_equal :
public std::binary_function<state const *, state const *, bool>
{
bool operator()(state const * a, state const * b) const {
return a->player->x == b->player->x &&
a->player->y == b->player->y &&
a->box[0].x == b->box[0].x &&
a->box[0].y == b->box[0].y;
}
};
Now we need a predicate that will return true if the given item is found within another container. This part admittedly may be a bit hard to follow if you are not familiar with the algorithms library.
template <typename Iterator, typename Comparer>
struct is_in_container_func :
public std::unary_function<
typename std::iterator_traits<Iterator>::value_type const &,
bool
>
{
is_in_container_func(Iterator begin, Iterator end, Comparer cmp)
: it_begin(begin), it_end(end), comparer(cmp) { }
bool operator()(argument_type i) const {
return std::find_if(it_begin, it_end, std::bind1st(comparer, i)) != it_end;
}
private:
Iterator it_begin;
Iterator it_end;
Comparer comparer;
};
// This is just a helper to allow template type deduction; its only purpose is to
// allow us to omit the types for Iterator and Comparer when constructing an
// is_in_container_func object.
template <typename Iterator, typename Comparer>
is_in_container_func<Iterator, Comparer> is_in_container(
Iterator begin, Iterator end, Comparer cmp)
{
return is_in_container_func<Iterator, Comparer>(begin, end, cmp);
}
Now we can put all of these pieces together with std::remove_if:
std::vector<state*> vectorOpen;
std::vector<state*> vectorClosed;
std::vector<state*> vectorCheck;
// Make one pass, removing elements if they are found in vectorOpen.
std::vector<state*>::iterator new_end = std::remove_if(
vectorCheck.begin(), vectorCheck.end(),
is_in_container(vectorOpen.begin(), vectorOpen.end(), states_are_equal()));
// Make another pass, removing elements if they are found in vectorClosed.
new_end = std::remove_if(
vectorCheck.begin(), new_end,
is_in_container(vectorClosed.begin(), vectorClosed.end(), states_are_equal()));
// std::remove_if just swaps elements around so that the elements to be removed are
// all together at the end of the vector, and new_end is an iterator to the first
// one. So, finally, we just need to remove the range [new_end, end()).
vectorCheck.erase(new_end, vectorCheck.end());
The erase call invalidates the iterator passed to it. It shifts the elements in the vector one place to their left, and returns an iterator to the element after the removed one. Therefore, you should not increment the iterator if the erase was executed. Like so:
for(itCheck = vectorCheck.begin(); itCheck != vectorCheck.end();) { // no increment
bool found = false;
for(itOpen = vectorOpen.begin(); itOpen != vectorOpen.end(); itOpen++) {
if ((*itCheck)->player->x == (*itOpen)->player->x &&
(*itCheck)->player->y == (*itOpen)->player->y &&
(*itCheck)->box[0].x == (*itOpen)->box[0].x &&
(*itCheck)->box[0].y == (*itOpen)->box[0].y) {
cout << "erasing as in open " << (*itCheck)->player->x << " " << (*itCheck)->player->y << " " << (*itCheck)->box[0].x << " " << (*itCheck)->box[0].y << endl;
itCheck = vectorCheck.erase(itCheck);
found = true;
break; // found element and erased it. back to outer loop
}
}
if (!found) ++itCheck; // didn't find it, need to increment
}
Given the minimal C++11 STL example:
set<int> S = {1,2,3,4};
for(auto &x: S) {
cout << x;
cout << ",";
}
Is there a way to check if x is the one right before the end? The goal in this example is to output 1,2,3,4 and not the final comma at the end. Currently I use a standard for loop with two iterators,
set<int>::const_iterator itr;
set<int>::const_iterator penultimate_end_itr = --S.end();
for(itr=S.begin(); itr!=penultimate_end_itr;++itr)
cout << (*itr) << ',';
cout << (*penultimate_end_itr);
Which works, but is terribly cumbersome. Is there a way to do the check within the range-based for loop?
EDIT: The point of the question is not to print out a comma separated list. I want to know if a range-based for loop has any knowledge of the penultimate element in the list (i.e. is it one before the end). The minimal example was presented so we all have a common code block to talk about.
The very purpose of range-based for loops is to forget the iterator. As such, they only allow you access to the current value and not the iterator. Would the following code do it for you?
set<int> S = {1,2,3,4};
std::string output;
for(auto &x: S) {
if (!output.empty())
output += ",";
output += to_string(x);
}
cout << output;
EDIT
Another solution: Instead of comparing iterators (as one would do with "normal" for loops), you could compare the addresses of the values:
set<int> S = {1,2,3,4};
auto &last = *(--S.end());
for (auto &x : S)
{
cout << x;
if (&x != &last)
cout << ",";
}
Boost.Range can help out here:
if (std::begin(S) != std::end(S)) {
std::cout << *std::begin(S);
for (const auto &x: boost::make_iterator_range(std::next(std::begin(S)), std::end(S))) {
std::cout << ", " << x;
}
}
A much more flexible approach is to index the range, using boost::adaptors::indexed (since Boost 1.56):
for (const auto &element: boost::adaptors::index(S)) {
std::cout << (element.index() ? ", " : "") << element.value();
}
In versions of Boost prior to 1.56 boost::adaptors::indexed won't work but you can easily write a work-alike:
template <typename... T>
auto zip(const T&... ranges) -> boost::iterator_range<boost::zip_iterator<decltype(boost::make_tuple(std::begin(ranges)...))>>
{
auto zip_begin = boost::make_zip_iterator(boost::make_tuple(std::begin(ranges)...));
auto zip_end = boost::make_zip_iterator(boost::make_tuple(std::end(ranges)...));
return boost::make_iterator_range(zip_begin, zip_end);
}
template<typename T>
auto enumerate(const T &range) -> boost::iterator_range<boost::zip_iterator<boost::tuple<
boost::counting_iterator<decltype(boost::distance(range))>, decltype(std::begin(range))>>>
{
return zip(boost::make_iterator_range(boost::make_counting_iterator(0),
boost::make_counting_iterator(boost::distance(range))), range);
}
for (const auto &tup: enumerate(S)) {
std::cout << (tup.get<0>() ? ", " : "") << tup.get<1>();
}
This is using the zip function from Sequence-zip function for c++11?