I am trying to create a data structure called Disjoint Set. Looking at theory what i thought of is something like this :
std::vector<std::pair<int,std::set<int>>> DisjointSet;
for(auto i=0;i<10;++i) DisjointSet.push_back( std::make_pair(i,std::set<int>().insert(i)));
but this code gives which is beyond my understanding , so this is good design to make Disjoint Set. Also how do i get rid of these errors?
set::insert doesn't return the set itself. You need to create the set beforehand, insert and then use it in make_pair. This does the trick with nearly no overhead for the copy using move:
std::vector< std::pair<int,std::set<int> > > DisjointSet;
for(auto i=0;i<10;++i) {
std::set<int> tmp; tmp.insert(i);
DisjointSet.push_back( std::make_pair(i,std::move(tmp)));
}
Well the following code does what I think you were attempting
std::vector< std::pair< int, std::set<int> > > DisjointSet;
for (int i=0; i<10; ++i)
{
std::set<int> tmp;
tmp.insert(i);
DisjointSet.push_back( std::make_pair(i,tmp) );
}
std::set<int>().insert(i)
does not return std::set.
Try to do it in several lines:
for(int i=0;i<10;++i) {
DisjointSet.push_back( std::make_pair(i,std::set<int>()) );
DisjointSet.back().insert(i);
}
You have a call to insert which makes no sense (since it doesn't return the set). So
std::vector<std::pair<int,std::set<int>>> DisjointSet;
for(auto i=0;i<10;++i)
DisjointSet.push_back( std::make_pair(i,std::set<int>().insert(i)));
Should really be something along the lines of
std::vector<std::pair<int,std::set<int>>> DisjointSet;
std::set<int> temp;
for(auto i=0;i<10;++i)
{
temp.insert(i)
DisjointSet.push_back( std::make_pair(i,temp) );
temp.clear();
}
A little more verbose, but its correct.
Related
I am trying to make something like this:
v.erase(remove_if(v.begin(), v.end(), !pointer_to_func), v.end());
where v is a vector of strings, and pointer_to_func is my function-pointer that looks something like this:
bool (*pointer_to_func)(std::string);
And I know that the !pointer_to_func is wrong, however, that is the algorithm I am looking to produce somehow given the circumstances.
This is how it is declared in the class :
void Place::filter_ss(bool (*n)(std::string)){}; //function pointer labeled FP
I have searched all over, and I am not sure what else to do. Given that the function calls for filtering words in a vector to meet substring conditions, I figured remove_if() and copy() mash-up would do the trick however, I was wrong, and all options I have seen are deprecated/removed (i.e. not1, not2, ptr_fun, etc.).
Function is called as such in main program file:
int main(){
//places all push_back into vector v
Place p(){"Observatory", "Airport", "Delicatessen", "Theater", "Vacation"};
//this function is the pain, it take in the string directly and erases words not containing the substring
p.filter_ss(at);
//for loop should output: Observatory Delicatessen Theater Vacation
for (size_t x = 0; x < p.v.size(), x++)
cout << v[x] << " ";
... //Do something
... //Do something more
return 0;
}
My code only works with predefined test functions for example:
bool st(string str){
return str.find("st") < string::npos;
}
Any assistance/direction would be appreciated.
attempts aren't in order, nor are they alone in their own unique possibilities. These are general ideas of some of the things I have tried:
1.
void Place::filter_ss(bool (*n)(string)){
pointer_to_func = n;
vector<string> temp;
for(size_t t = 0; t < v.size(); t++){
if(pointer_to_func(v[t])){
temp.push_back(v[t]);
}
}
v.clear();
for(auto s : temp)
v.push_back(s);
}
2.
void Place::filter_ss(bool (*n)(string)){
pointer_to_func = n;
v.erase(remove_if(v.begin(), v.end(), not1(ptr_fun(pointer_to_func))), v.end());
}
3.
void Place::filter_ss(bool (*n)(string)){
vector<string> temp;
pointer_to_func = n;
copy_if(temp.begin(), temp.end(), back_inserter(v), pointer_to_func);
}
The various std::not functors were deprecated in C++17 and removed from C++20 because they added a better, generic alternative: std::not_fn:
v.erase(remove_if(v.begin(), v.end(),
std::not_fn(pointer_to_func), v.end());
I have a program where I have to delete some entries of a vector of structs. Im doing it like this
for(int i=0; i<molec.size(); i++)
{
if(!molec[i].mine)
molec.erase(molec.begin()+i);
}
molec.mine is a boolean defined in the struct. The problem is that when I do this, it erases exactly half of the elements with molec.mine=false. I tried to search for some alternatives and found that I could do it with
vector.erase(std::remove(vec.begin(),vec.end(),1963),vec.end());
The thing with this is that I don't know how to do it with a vector of structs.
How can I solve this problem?
You are probably looking for std::remove_if. As in
molec.erase(
std::remove_if(
molec.begin(), molec.end(),
[](const auto& elem) { return !elem.mine; }),
molec.end());
i++ shouldn't be performed when element is erased. e.g.
for(int i=0; i<molec.size(); )
{
if(!molec[i].mine)
molec.erase(molec.begin()+i);
else
i++;
}
And yes, you should use algorithm library to avoid such issues.
molec.erase(std::remove_if(molec.begin(),molec.end(),[](const auto& v) { return !v.mine;}),molec.end());
I am trying to learning more about maps in general:
i have never seen syntax like this before:
charMap[c]++;
i assume it is adding a char into as key? and incrementing the count as value? Would someone be able to provide where i can see this notation? I cant seem to find any information of this.
int firstUniqChar(string s) {
unordered_map<char, int> charMap;
for (char c : s)
charMap[c]++;
}
Also I was wondering, how come i receive an error when I try to insert into map but it works when i do map?
int firstUniqChar(string s) {
map<string,int> myMap;
for( int i=0; i<s.length(); i++){
auto it = myMap.insert({s[i],1});
if(!it.second){
it.first->second+=1;
}
}
auto itr = myMap.begin();
while(itr!=myMap.end()){
cout<<it->first;
it++;
}
}
unordered_map<char, int> charMap;
charMap[c]++;
std::map::operator[]:
Returns a reference to the value that is mapped to a key equivalent to key, performing an insertion if such key does not already exist.
So charMap[c] returns a reference to the mapped int that is increased with ++.
auto it = myMap.insert({s[i], 1});
There's no matching insert overload. Try using emplace:
auto it = myMap.emplace(s[i], 1);
Edit: I just noticed that you changed to a map with a string as key in your second part of the code and that you probably try to create a string from the char s[i] with length 1 when you do {s[i],1}, but that's the wrong way around. The count comes first, then the char - it also lacks the value part.
Using insert it could look like below. I'm using structured bindings to make it easier to see what's what.
map<string,int> myMap;
for(size_t i=0; i<s.length(); i++){
// create a string of length 1 mapped to the value 1
auto [it, inserted] = myMap.insert({{1, s[i]}, 1});
auto& [key, value] = *it;
if(inserted == false) {
++value;
}
}
As the title says, I want to add an element to a std::vector in certain cases while iterating through the vector. With the following code, I'm getting an error "Debug assertion failed". Is it possible to achieve what I want to do?
This is the code I have tested:
#include <vector>
class MyClass
{
public:
MyClass(char t_name)
{
name = t_name;
}
~MyClass()
{
}
char name;
};
int main()
{
std::vector<MyClass> myVector;
myVector.push_back(MyClass('1'));
myVector.push_back(MyClass('2'));
myVector.push_back(MyClass('3'));
for each (MyClass t_class in myVector)
{
if (t_class.name == '2')
myVector.push_back(MyClass('4'));
}
return 0;
}
EDIT:
Well, I thought for each was standard C++, but it seems that it's a Visual Studio feature:
for each, in
Visual c++ "for each" portability
The act of adding or removing an item from a std::vector invalidates existing iterators. So you cannot use any kind of loop that relies on iterators, such as for each, in, range-based for, std::for_each(), etc. You will have to loop using indexes instead, eg:
int main()
{
std::vector<MyClass> myVector;
myVector.push_back('1');
myVector.push_back('2');
myVector.push_back('3');
std::vector<MyClass>::size_type size = myVector.size();
for (std::vector<MyClass>::size_type i = 0; i < size; ++i)
{
if (myVector[i].name == '2')
{
myVector.push_back('4');
++size; // <-- remove this if you want to stop when you reach the new items
}
}
return 0;
}
As pointed out by pyon, inserting elements into a vector while iterating over it (via iterators) doesnt work, because iterators get invalidated by inserting elements. However, it seems like you only want to push elements at the back of the vector. This can be done without using iterators but you should be careful with the stop condition:
std::vector<MyClass> myVector;
size_t old_size = myVector.size();
for (int i=0;i<old_size;i++) {
if (myVector[i].name == '2') { myVector.push_back(MyClass('4')); }
}
After following the previous answers, you can use const auto& or auto& to have clean code. Should be optimized in release build by the compiler.
std::vector<MyClass> myVector;
std::vector<MyClass>::size_type size = myVector.size();
for (std::vector<MyClass>::size_type i = 0; i < size; ++i)
{
const auto& element = myVector[i];
element.do_stuff();
}
Suppose now I have a list of data which is kept in a vector a. What I am going to do is to check whether each element in the data list is satisfied with some criteria. If it does, it will be removed from a and then be kept in another vector b. For example, in the following codes I can easily finish this task:
class findOddClass
{
public:
int Common;
findOddClass(int common):Common(common){};
bool operator()(const int &i)
{
return (i%Common == 1);
}
};
void testFunctionObject()
{
std::vector<int> objArray;
for(int i=0; i<10; i++)
objArray.push_back(i);
findOddClass finder(2);
std::vector<int>::iterator it = objArray.begin();
std::vector<int> oddArray;
while(it != objArray.end())
{
if (finder(*it))
{
oddArray.push_back(*it);
it = objArray.erase(it);
}
else
it++;
}
std::cout<<"Even array"<<std::endl;
for(it=objArray.begin(); it != objArray.end(); it++)
std::cout<<*it<<" ";
std::cout<<std::endl;
std::cout<<"Odd array"<<std::endl;
for(it= oddArray.begin(); it!=oddArray.end(); it++)
std::cout<<*it<<" ";
std::cout<<std::endl;
}
However, if I want to finish the same task with a more elegant way:
void testFunctionObject()
{
std::vector<int> objArray;
for(int i=0; i<10; i++)
objArray.push_back(i);
std::vector<int>::iterator itEnd;
itEnd = std::remove_if(objArray.begin(),objArray.end(),findOddClass(2));
std::vector<int> oddArray;
std::vector<int>::iterator it = itEnd;
while(it != objArray.end())
{
oddArray.push_back(*it);
it++;
}
objArray.erase(itEnd,objArray.end());
std::cout<<"Even array"<<std::endl;
for(it=objArray.begin(); it != objArray.end(); it++)
std::cout<<*it<<" ";
std::cout<<std::endl;
std::cout<<"Odd array"<<std::endl;
for(it= oddArray.begin(); it!=oddArray.end(); it++)
std::cout<<*it<<" ";
std::cout<<std::endl;
}
It will fail. The reason lies in the fact that std::removal_if will not keep a trace of the element that will be removed. I was just wondering whether there is a function in STL can do the job, hence a more elegant way of doing the job. Thanks.
I would suggest to use algorithm std::partition_copy if you want to split an original sequence in two sequences depending on some predicate. As the algorithm returns a pair of output iterators it will be easy to apply method erase using the result of the previous call of std::partition_copy
template <class InputIterator, class OutputIterator1,
class OutputIterator2, class Predicate>
pair<OutputIterator1, OutputIterator2>
partition_copy(InputIterator first, InputIterator last,
OutputIterator1 out_true, OutputIterator2 out_false,
Predicate pred);
std::partition is very efficient for moveable elements. Sketched out, the code would look something like this:
auto partition_point = std::partition(v1.begin(), v1.end(), predicate);
// Move the elements at the range to the other vector.
v2.assign(std::make_move_iterator(partition_point),
std::make_move_iterator(v1.end()));
// Remove the remains from the original.
v1.erase(partition_point, v1.end());
The advantage over the partition_copy solution is that there is zero actual copying going on, which make this more efficient for handle-like things like std::string, or move-only types.