Related
~ i'm learning c++ on my own~
I have a class field vector of objects that I want to iterate through and erase things that don't meet a certain condition.
myVector[0] is {obj1= val 1, obj2= val 2, obj3= val3 }
.
.
.
myVector[i] is {obj1= val x, obj2= val y, obj3= valz }
my issue is in order to pass the value to predicate function i need to access the object id and value at that index. But I don't know how to implement it so that i iterates/ increments.
Or more specifically how to I pass that key value at each index ? I'm asking for syntax help.
something like this:
myVector.erase(std::partition(myVector.begin(),myVector.end(), predicate(myVector[i].obj1)),myVector.end());
obviously there is no way for me to increment i this way.
is there a way to do this without using a for loop
I'm not 100% sure I understand the question, because you seem to be worried about the indexes into the vector. If your predicate needs to look at the indexes and not just the items in the vector, that complicates things.
However, does this solve your problem?
#include <algorithm>
myVector.erase(
std::remove_if(myVector.begin(), myVector.end(), myPredicate),
myVector.end());
This is an example of the so-called "erase / remove idiom." The call to remove_if shifts the elements you want to keep forward in the list the appropriate amount but doesn't truncate the vector. Instead, it returns a pointer to the end of the list, which you can then pass to erase.
(Why can't we do this just a single call, instead of having the confusingly-named erase AND remove together? Because std::remove_if is part of <algorithm>, which consists of generic algorithms that work on anything that supplies the right sort of iterators, whereas erase is special to std::vector. Having a start/end pair of the right sort of iterators gives you enough functionality to do what remove_if does, but doesn't give you the ability to truncate the list directly.)
You can write this using a lambda if you don't want to break the predicate out into its own method. For instance:
myVector.erase(
std::remove_if(myVector.begin(), myVector.end(),
[](const auto & x) { return x.obj1 <= 0; }),
myVector.end());
I need to return the bottom 10 elements in a map using a for_each algorithm. For some reason map iterators do not have random access so I cannot use:
std::for_each(std::map.end(), std::map.end()-10, <lambda>);
I can use the -- operator on the iterators, but I'd rather not use ten of those!
So can someone let me know if there is a way to specify that the algorithm should only consider 10 of the elements?
Use auto x = your_map.end(); std::advance(x, -10);.
Note that as you have the iterators now, however, that won't do much good. You need the beginning of the range first -- if you use whatever.end() as the first parameter to for_each, it won't work correctly.
If you want to iterate through the map in reverse order, you could use:
auto s your_map.rbegin();
advance(s, 10);
std::for_each(s, your_map.rend(), ...);
In C++11 you can use std::advance(iter, dist) instead of calling ++ or -- ten times. To go forward, pass positive dist; to go backward, pass a negative dist:
auto ten_before(map.end());
std::advance(ten_before, -1);
std::for_each(std::map.end(), ten_before, -10), <lambda>);
std::advance as the other answers recommend will work. But in C++11 it's more convenient to use std::prev, which returns the resulting iterator instead of changing the given iterator, so it can be used in a one-liner:
std::for_each(std::prev(mymap.end(), 10), mymap.end(), func);
Note: I fixed the order of iterators above, you had the iterators backwards in your example.
If you want to iterate the last 10 items in reverse order, starting from the last element, you can use reverse iterators and std::next:
std::for_each(mymap.rbegin(), std::next(mymap.rbegin(), 10), func);
This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Why use iterators instead of array indices?
I'm reviewing my knowledge on C++ and I've stumbled upon iterators. One thing I want to know is what makes them so special and I want to know why this:
using namespace std;
vector<int> myIntVector;
vector<int>::iterator myIntVectorIterator;
// Add some elements to myIntVector
myIntVector.push_back(1);
myIntVector.push_back(4);
myIntVector.push_back(8);
for(myIntVectorIterator = myIntVector.begin();
myIntVectorIterator != myIntVector.end();
myIntVectorIterator++)
{
cout<<*myIntVectorIterator<<" ";
//Should output 1 4 8
}
is better than this:
using namespace std;
vector<int> myIntVector;
// Add some elements to myIntVector
myIntVector.push_back(1);
myIntVector.push_back(4);
myIntVector.push_back(8);
for(int y=0; y<myIntVector.size(); y++)
{
cout<<myIntVector[y]<<" ";
//Should output 1 4 8
}
And yes I know that I shouldn't be using the std namespace. I just took this example off of the cprogramming website. So can you please tell me why the latter is worse? What's the big difference?
The special thing about iterators is that they provide the glue between algorithms and containers. For generic code, the recommendation would be to use a combination of STL algorithms (e.g. find, sort, remove, copy) etc. that carries out the computation that you have in mind on your data structure (vector, list, map etc.), and to supply that algorithm with iterators into your container.
Your particular example could be written as a combination of the for_each algorithm and the vector container (see option 3) below), but it's only one out of four distinct ways to iterate over a std::vector:
1) index-based iteration
for (std::size_t i = 0; i != v.size(); ++i) {
// access element as v[i]
// any code including continue, break, return
}
Advantages: familiar to anyone familiar with C-style code, can loop using different strides (e.g. i += 2).
Disadvantages: only for sequential random access containers (vector, array, deque), doesn't work for list, forward_list or the associative containers. Also the loop control is a little verbose (init, check, increment). People need to be aware of the 0-based indexing in C++.
2) iterator-based iteration
for (auto it = v.begin(); it != v.end(); ++it) {
// if the current index is needed:
auto i = std::distance(v.begin(), it);
// access element as *it
// any code including continue, break, return
}
Advantages: more generic, works for all containers (even the new unordered associative containers, can also use different strides (e.g. std::advance(it, 2));
Disadvantages: need extra work to get the index of the current element (could be O(N) for list or forward_list). Again, the loop control is a little verbose (init, check, increment).
3) STL for_each algorithm + lambda
std::for_each(v.begin(), v.end(), [](T const& elem) {
// if the current index is needed:
auto i = &elem - &v[0];
// cannot continue, break or return out of the loop
});
Advantages: same as 2) plus small reduction in loop control (no check and increment), this can greatly reduce your bug rate (wrong init, check or increment, off-by-one errors).
Disadvantages: same as explicit iterator-loop plus restricted possibilities for flow control in the loop (cannot use continue, break or return) and no option for different strides (unless you use an iterator adapter that overloads operator++).
4) range-for loop
for (auto& elem: v) {
// if the current index is needed:
auto i = &elem - &v[0];
// any code including continue, break, return
}
Advantages: very compact loop control, direct access to the current element.
Disadvantages: extra statement to get the index. Cannot use different strides.
What to use?
For your particular example of iterating over std::vector: if you really need the index (e.g. access the previous or next element, printing/logging the index inside the loop etc.) or you need a stride different than 1, then I would go for the explicitly indexed-loop, otherwise I'd go for the range-for loop.
For generic algorithms on generic containers I'd go for the explicit iterator loop unless the code contained no flow control inside the loop and needed stride 1, in which case I'd go for the STL for_each + a lambda.
With a vector iterators do no offer any real advantage. The syntax is uglier, longer to type and harder to read.
Iterating over a vector using iterators is not faster and is not safer (actually if the vector is possibly resized during the iteration using iterators will put you in big troubles).
The idea of having a generic loop that works when you will change later the container type is also mostly nonsense in real cases. Unfortunately the dark side of a strictly typed language without serious typing inference (a bit better now with C++11, however) is that you need to say what is the type of everything at each step. If you change your mind later you will still need to go around and change everything. Moreover different containers have very different trade-offs and changing container type is not something that happens that often.
The only case in which iteration should be kept if possible generic is when writing template code, but that (I hope for you) is not the most frequent case.
The only problem present in your explicit index loop is that size returns an unsigned value (a design bug of C++) and comparison between signed and unsigned is dangerous and surprising, so better avoided. If you use a decent compiler with warnings enabled there should be a diagnostic on that.
Note that the solution is not to use an unsiged as the index, because arithmetic between unsigned values is also apparently illogical (it's modulo arithmetic, and x-1 may be bigger than x). You instead should cast the size to an integer before using it.
It may make some sense to use unsigned sizes and indexes (paying a LOT of attention to every expression you write) only if you're working on a 16 bit C++ implementation (16 bit was the reason for having unsigned values in sizes).
As a typical mistake that unsigned size may introduce consider:
void drawPolyline(const std::vector<P2d>& points)
{
for (int i=0; i<points.size()-1; i++)
drawLine(points[i], points[i+1]);
}
Here the bug is present because if you pass an empty points vector the value points.size()-1 will be a huge positive number, making you looping into a segfault.
A working solution could be
for (int i=1; i<points.size(); i++)
drawLine(points[i - 1], points[i]);
but I personally prefer to always remove unsinged-ness with int(v.size()).
PS: If you really don't want to think by to yourself to the implications and simply want an expert to tell you then consider that a quite a few world recognized C++ experts agree and expressed opinions on that unsigned values are a bad idea except for bit manipulations.
Discovering the ugliness of using iterators in the case of iterating up to second-last is left as an exercise for the reader.
Iterators make your code more generic.
Every standard library container provides an iterator hence if you change your container class in future the loop wont be affected.
Iterators are first choice over operator[]. C++11 provides std::begin(), std::end() functions.
As your code uses just std::vector, I can't say there is much difference in both codes, however, operator [] may not operate as you intend to. For example if you use map, operator[] will insert an element if not found.
Also, by using iterator your code becomes more portable between containers. You can switch containers from std::vector to std::list or other container freely without changing much if you use iterator such rule doesn't apply to operator[].
It always depends on what you need.
You should use operator[] when you need direct access to elements in the vector (when you need to index a specific element in the vector). There is nothing wrong in using it over iterators. However, you must decide for yourself which (operator[] or iterators) suits best your needs.
Using iterators would enable you to switch to other container types without much change in your code. In other words, using iterators would make your code more generic, and does not depend on a particular type of container.
By writing your client code in terms of iterators you abstract away the container completely.
Consider this code:
class ExpressionParser // some generic arbitrary expression parser
{
public:
template<typename It>
void parse(It begin, const It end)
{
using namespace std;
using namespace std::placeholders;
for_each(begin, end,
bind(&ExpressionParser::process_next, this, _1);
}
// process next char in a stream (defined elsewhere)
void process_next(char c);
};
client code:
ExpressionParser p;
std::string expression("SUM(A) FOR A in [1, 2, 3, 4]");
p.parse(expression.begin(), expression.end());
std::istringstream file("expression.txt");
p.parse(std::istringstream<char>(file), std::istringstream<char>());
char expr[] = "[12a^2 + 13a - 5] with a=108";
p.parse(std::begin(expr), std::end(expr));
Edit: Consider your original code example, implemented with :
using namespace std;
vector<int> myIntVector;
// Add some elements to myIntVector
myIntVector.push_back(1);
myIntVector.push_back(4);
myIntVector.push_back(8);
copy(myIntVector.begin(), myIntVector.end(),
std::ostream_iterator<int>(cout, " "));
The nice thing about iterator is that later on if you wanted to switch your vector to a another STD container. Then the forloop will still work.
its a matter of speed. using the iterator accesses the elements faster. a similar question was answered here:
What's faster, iterating an STL vector with vector::iterator or with at()?
Edit:
speed of access varies with each cpu and compiler
I am trying to rotate a vector of elements in C++. What I mean by that is that I have a vector<point> I want the last element to become the first.
Example:
[1,2,3] become [3,1,2] then [2,3,1]
For that I tried to do the following:
//Add the last element at index 0
ObjectToRotate.insert(0, ObjectToRotate.at(ObjectToRotate.size()-1));
//Remove Last element
ObjectToRotate.erase(ObjectToRotate.size()-1);
but I get this error:
Error 6 error C2664: 'std::_Vector_iterator<_Myvec> std::vector<Ty>::insert<cv::Point<_Tp>&>(std::_Vector_const_iterator<_Myvec>,_Valty)' : cannot convert parameter 1 from 'int' to 'std::_Vector_const_iterator<_Myvec>'
How can I solve it?
There's a std::rotate algorithm in the standard library:
std::rotate(ObjectToRotate.begin(),
ObjectToRotate.end()-1, // this will be the new first element
ObjectToRotate.end());
The recommendations to use std::rotate are, of course, fully correct;
using an existing function is always the preferred solution when
available. Never the less, it's worth pointing out why your solution
didn't work. Containers in the standard library, like std::vector,
take position information in the form of iterators, not indexes. The
idiomatic way of writing your operation would be:
v.insert( v.begin(), v.back() );
v.erase( std::prev( v.end() ) );
(If you don't have C++11, it's pretty simply to write your own version
of prev. Or in the case of vector, you can just write v.end() -
1.)
The arguments to insert and erase are iterators, not indexes:
ObjectToRotate.insert(ObjectToRotate.begin(), ObjectToRotate.back());
ObjectToRotate.pop_back(); // or erase(ObjectToRotate.end()-1), if you prefer
But it may be more efficient to remove the last element first (after taking a copy), to avoid the possibility of reallocation:
auto back = ObjectToRotate.back();
ObjectToRotate.pop_back();
ObjectToRotate.insert(ObjectToRotate.begin(), back);
or to use std::rotate:
std::rotate(ObjectToRotate.begin(), ObjectToRotate.end()-1, ObjectToRotate.end());
If you're doing this a lot, then deque might be a better choice of container, since that allows efficient insertion and removal at both ends. But, if speed is important, make sure you measure and verify that this really is an improvement; if the sequence isn't very large, then the overhead from the more complicated memory layout might make deque slower.
Use std::rotate: http://en.cppreference.com/w/cpp/algorithm/rotate
James Kanze suggested a fantastic answer of using the following code snippet to rotate individual elements. To rotate x amount of items, simply put the below code into a loop.
vec.insert( vec.begin(), vec.back() );
vec.erase( std::prev( vec.end() ) );
If you CAN use the standard rotate function, that'll be your best choice, however. The code below is again rotating x number of items, see the CPP docs about rotate, and they even provide code examples showing Left & Right rotation. :)
// simple rotation to the left
std::rotate(vec.begin(), vec.begin() + x, vec.end());
// simple rotation to the right
std::rotate(vec.rbegin(), vec.rbegin() + x, vec.rend());
for making [1,2,3] to [2,3,1] here is the code
vector<int> Solution::rotateArray(vector<int> &A, int B) {
vector<int> ret;
for (int i = 0; i < A.size(); i++) {
ret.push_back(A[(i + B) % A.size()]);
}
return ret;
}
here A is [1,2,3] and B is 1 to shift 1 position
I have a std::list which I am currently randomizing using a Fisher-Yates shuffle (see http://en.wikipedia.org/wiki/Fisher-Yates_shuffle). To summarize, my code carries out the following steps on the list:
Loop through each element of the list.
Swap the element with a randomly chosen element from the current position onwards, including itself.
Because lists don't provide random access, this means that I am iterating over the entire list in step 1, and for each element I'm iterating again, on average over half the remaining elements from that point onwards. This is a major bottleneck in my program's performance, so I'm looking to improve it. For other reasons I need to continue using list as my container, but I'm considering converting to a vector at the start of my randomize function, and then converting back to list at the end. My lists typically contain 300 - 400 items, so I would guess that the cost of conversion between containers will be worth it to avoid traversing the items sequentially.
My question is: does this seem like the best way to go about optimizing the code? Is there a better way?
One easy improvement is to copy the data into a vector, shuffle the vector, and copy it back into a list. That is what was suggested in comments by Max and PeskyGnat:
vector<int> myVector(myList.size());
copy(myList.begin(), myList.end(), myVector.begin());
random_shuffle(myVector.begin(), myVector.end());
list<int> myListShuffled(myVector.begin(), myVector.end());
This implementation is pretty fast. But, it will do three passes over the vector, and you can get it down to two passes by implementing the shuffle yourself:
vector<int> myVector(myList.size());
int lastPos = 0;
for(list<int>::iterator it = myList.begin(); it != myList.end(); it++, lastPos++) {
int insertPos = rand() % (lastPos + 1);
if (insertPos < lastPos) {
myVector[lastPos] = myVector[insertPos];
}
myVector[insertPos] = *it;
}
list<int> myListShuffled(myVector.begin(), myVector.end());
Since the first version is much easier to understand and much less error-prone, it's almost always preferable... unless perhaps this bit of code is critical for your performance (and you confirmed that with measurement.)
EDIT: By the way, since you are looking at the Wikipedia article, the second code sample uses the "inside-out" variant of Fisher-Yates.