Removing a string from a std::vector? [closed] - c++

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 6 years ago.
Improve this question
I have a std::vector<string> called v. I'd like to read in a string from the user and remove it from v. Here's what I have so far:
string rnames;
cout << "Enter the string to remove " << endl;
cin >> rnames;
v.erase(rnames);
This produces an error.
Any ideas how we can make this to work? Do we first need to find the rnames and then erase it?

The std::vector's erase method takes in an iterator saying which entry in the vector you want to remove. It doesn't work like the map or set where you can call erase to remove a specified key.
To remove a single copy of an element from a std::vector, you can use std::find and the std::vector's erase member function like this:
auto itr = std::find(v.begin(), v.end(), rnames);
if (itr != v.end()) v.erase(itr);
The above code assumes you're using C++11, which all major modern compilers support. However, it seems like you're using an older compiler that doesn't support C++11, so you'd have to write something like this:
std::vector<string>::iterator itr = std::find(v.begin(), v.end(), rnames);
if (itr != v.end()) v.erase(itr);
To remove all copies of an element from a vector, you can use std::remove like this:
v.erase(std::remove(v.begin(), v.end(), rnames), v.end());
(This requires the <algorithm> header.) That being said, if you find that you are often removing elements from a std::vector and you have a large number of elements in the vector, you may want to consider changing data structures to something that more efficiently supports removals.

Related

Is there any advantage of using a range for loop rather than an iterator? [closed]

Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 1 year ago.
This post was edited and submitted for review 7 months ago and failed to reopen the post:
Original close reason(s) were not resolved
Improve this question
for (auto& i : just_a_vec )
Or an iterator for loop.
for (std::vector<std::string>::iterator it = just_a_vec.begin(); it < just_a_vec.end(); it++)
Iterators predate range-based for loops, so they used to be the only of these two alternatives available. Nowadays, range-based for has mostly replaced iterators when dealing with a simple loop.
However, iterators can be used in various other contexts as well. For example, you can do std::sort(v.begin(), std::next(v.begin(), 5)) to sort the first five elements of a vector while leaving the rest of it alone.
Going back to iterating over a whole container:
If you can accomplish what you want with a range-based for, then it leads to more legible code, so they are preferable by default.
If you need iterators for some reason, such as using an algorithm that requires them, or because you need to jump ahead or back while iterating, then use those instead.
Also: In the later case, you can/should still use auto when declaring the iterator:
for(auto it = just_a_vec.begin(); it < just_a_vec.end(); it++) {
}
Edit: as asked: here's a simple, if a bit contrived, example where an iterator-based loop can still be useful:
// adds all values in the vector, but skips over twos values when encountering a 0
// e.g.: {1,2,0,4,5,2} => 5
int my_weird_accum(const std::vector<int>& data) {
int result = 0;
for(auto it = data.begin(); it != data.end(); ++it) {
auto v = *it;
result += v;
if(v == 0) {
// skip over the next two
assert(std::distance(it, data.end()) > 2);
std::advance(it, 2);
}
}
return 0;
}
Quick personal answer: Its somewhat sylistic and based on what version of c++ you are using. I typically prefer range based, but there are certainly moments iterators shine as well. Add both to your toolchest. For further reading.
Here is a list of other SO answers that get more into the performance and use cases.
What's the difference between iterator syntax in range-based loops for STL containers
Is the ranged based for loop beneficial to performance?
range based for loop vs regular iterator for loop
For further information. Google
Range vs iterator loop c++

C++ set allowing duplicates? [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 1 year ago.
Improve this question
I am attempting to solve the interview problem from leet code to remove duplicates from a vector of ints.
Below is my my code for the answer:
#include <vector>
#include <set>
using namespace std;
class Solution {
public:
int removeDuplicates(vector<int>& nums) {
vector<int>::iterator itr;
set<int> temp;
for (itr = nums.begin(); itr != nums.end(); itr++) {
if (temp.insert(*itr).second == false) {
nums.erase(itr);
}
}
return nums.size();
}
};
I've added includes for completion.
The problem I've run into is if I have an input vector as so [0,0,1,1,2,2,3,3,4,4,5,5] my function will only erase the duplicates that are not 1 or 2.
Thus my answer will be [0,1,1,2,2,3,4,5]. My understanding is that set will not allow duplicate values but I don't understand why 1 and 2 is still duplicated.
This is because this is undefined behavior.
nums.erase(itr);
std::vector's erase() method invalidates all existing iterators "at or after the point of the erase". Since itr is the "point of the erase", itr is no longer a valid iterator when erase() returns. Subsequent attempt to increment it, in the for loop's iteration results in undefined behavior.
Your C++ textbook will have a more complete explanation of how to use the value that erase() returns, and what it means, in order to correctly avoid undefined behavior; but the capsule summary is:
itr=nums.erase(itr);
Note that now itr points to the value in the vector that's already after what was erase()d, which might be end(); whether it's end() or not you obviously don't want to increment it immediately. It should be obvious that you want to check if the immediately following value in the vector is another duplicate too, don't you agree?
So what you'll need to slightly rework your loop so that it:
Uses erase() correctly
Only increments the iterator if it does not erase() the duplicate value.

Different iterator for for loop in one code [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 6 years ago.
Improve this question
I am creating function, which takes a vector of operators( different matrices). Operators can be provided in different ordering ( from the smallest to biggest or other way around).
I need to create for loop based on ordering
for(auto tr = operators.begin(); tr != operators.end() ; ++tr )
or
for(auto tr = operators.end(); tr != operators.begin() ; --tr )
content inside of loop stays same
is there any way how to do this automatically? maybe based on some help input parameter?
You can support this by having your function consume a pair of iterators (a "range") instead of a complete matrix or vector. For example:
template <typename Iterator>
void print(Iterator begin, Iterator end) {
for(auto tr = begin; tr != end; ++tr)
; // ...
}
This way, you can pass any sort of range in: forward, reverse, or others. This is how much of the STL is designed.
If you use a std::vector for example, you'd invoke the above like so:
std::vector<int> vec;
print(vec.begin(), vec.end()); // forward
print(vec.rbegin(), vec.rend()); // reverse
Although, technically, an end() iterator can often be decremented and dereferenced safely, you are relying on specific properties that not all iterators are guaranteed to have.
A number of standard containers [some introduced in C++11 do not] have both forward iterators (which iterate through elements in order) and reverse iterators (which iterate over elements in the opposite order). The counterparts of begin() and end() are rbegin() and rend() respectively.

Using algorithms with integer ranges [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 8 years ago.
Improve this question
Is it any nice way to call STL algorithms on an integer range?
For example I have a collection "col" with access to it's elements only via GetElement(int) method. Is it possible to use find_if function to find something in that collection?
I would like to call something like that:
auto element =
find_if(0, col.Size(), [&col] (int i) {
return predicate(col.GetElement(i));
});
I'm looking for an STL or any other library solution.
With standard C++? Yes, if you write a custom element iterator. Then, your code is easily simplified to:
auto element = find_if(col.begin(), col.end(), predicate);
It's not possible to do something closer to what you had in mind with the standard library, but it is with Boost, which is an incredible C++ library that you really ought to have. Boost has a counting iterator: http://www.boost.org/doc/libs/1_55_0/libs/iterator/doc/counting_iterator.html
How would you fill up a vector with the numbers zero through one hundred using std::copy()? The only iterator operation missing from builtin integer types is an operator*() that returns the current value of the integer. The counting iterator adaptor adds this crucial piece of functionality to whatever type it wraps. One can use the counting iterator adaptor not only with integer types, but with any incrementable type.
#include <boost\counting_iterator.hpp> //or something, not sure of exact header
int main() {
boost::counting_iterator<int> first(0);
boost::counting_iterator<int> last(col.Size());
auto element = find_if(first, last, [&col](int i) {return predicate(col.GetElement(i);});
}
Additionally, boost also has ranges. They don't really help you much in this exact situation, but it's related, so I'll mention it:
#include <boost\range\irange.hpp>
int main() {
for (int index: boost::range::irange<int>(0, col.Size()) )
{
std::cout << element; //counts from 0 to col.Size()
}
}

How to use iterator to iterate a 2D vector? [closed]

Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
Questions concerning problems with code you've written must describe the specific problem — and include valid code to reproduce it — in the question itself. See SSCCE.org for guidance.
Closed 9 years ago.
Improve this question
all
I am using vector in C++ STL to store my data. I pass and return them into and from functions. However, as the data size grows, the program is slower and slower. Thus I am updating the codes to an "iterator version".
What I want to archieve is that use iterators to pass, return and iterate STL vectors.
I am now ok with the operations with 1-dimensional vector, just like manipulating the arrays. However, when it comes to 2-dimensional vector, I am a bit confused.
Can anyone show me a simple code example that how to iterate a 2D vector using STL iterator?
Many thanks in advance.
Regards
Long
You state that your basic problem is performance, right?
You assume that this is caused due to copying.
Perhaps there could be simpler solutions for your problem:
Check if vectors can be passed by (const) reference
Check if shared_ptr makes sense
Consider if move semantics can help
Perhaps compiler version or implementation prevent return value optimization
If you need to know the size of a vector, and have two iterators it1 it2,
std::distance(it1, it2);
will tell you the distance between them. This will happen to be the size if they are begin and end
If you have a function like
int work(std::vector<int> items)
{
//...
}
this copies the vector items, so will use more RAM and take longer.
Sending a const ref instead will not copy the vector. Making it const stops you changing it, which might not help you, but you haven't posted any code so I don't know what you want to do.
int work(const std::vector<int> & items)
{
//...
}
Well its already somewhere on stackoverflow
But if you don't want to search here it is :
std::vector<std::vector<int> > vec{ {1,2,3},{4,5,6}};
//Simplest Way:- (C++11)
for(auto row:vec)
{
for(auto col:row)
std::cout<<col<< " ";
std::cout<<std::endl;
}
//OR Using iterator
std::vector<std::vector<int> >::iterator r;
std::vector<int>::iterator c;
for (r = vec.begin(); r != vec.end(); r++) {
for (c = r->begin(); c != r->end(); c++) {
std::cout<<*c<< " ";
}
std::cout<<std::endl;
}
Can get distance only between two iterators of same container
std::vector<int>::iterator s = v2.begin(); //Can be any start
std::vector<int>::iterator e = v2.end(); // Can be any end
std::cout<<"Distance :"<<std::distance(s,e)<<std::endl;