Reputation: 27
EDITED AT BOTTOM
If you're wondering about how to do this read the accepted answer, it works perfectly
Okay so I've been trying to figure this out for a couple of days now, I've read a bunch of peoples answers but for some reason I keep getting a compiling error when I try to delete duplicates in my program below. Is there a special way that I need to delete these duplicates because of how I set up the vector? Please help, I'm getting extremely frustrated that I can't figure this out.
//libraries
#include <iostream>
#include <string>
#include <set>
#include <fstream>
#include <vector>
#include <list>
#include <algorithm>
//class
class Name_Sorter
{
private:
//none
public:
//Name_Sorter();
//~Name_Sorter();
std::string name;
void get_Names(std::string person_Name ){ name = person_Name; }
void output_Names();
};
//get the user file
std::string get_File()//get input file
{
std::ifstream fin;
std::string file_To_Open;
std::cout << "What is the name of the file where you have stored the names? ";
getline(std::cin, file_To_Open);
//std::cout << file_To_Open; // for testing
return file_To_Open;
}
//output
void Name_Sorter::output_Names()
{
std::cout << "Name: " << name << std::endl;
}
//sort
bool comp(const Name_Sorter &t1, const Name_Sorter &t2) //definition
{
return t1.name < t2.name;
}//compare function
//main program
int main(int argc, const char * argv[])
{
//variables and vector
std::vector<Name_Sorter> info;
std::string names;
std::string file_To_Open;
std::ifstream fin;
int nameCounter = 0;
Name_Sorter *name_Data;
//get the file
file_To_Open = get_File();
fin.open(file_To_Open.c_str());
if (!fin.good()) throw "I/O Error";
//get name
while(!fin.eof())
{
fin >> names;
fin.ignore(1000, 10);
name_Data = new Name_Sorter;
name_Data -> get_Names(names);
info.push_back(*name_Data);
delete name_Data;//MM
nameCounter++;
}//get names
fin.close();
//sorting through the vector by name
std::sort(info.begin(), info.end(), comp);
//delete duplicates ****Seems to be a problem here****
info.erase(std::unique(info.begin(), info.end()), info.end());
std::vector<Name_Sorter>::iterator iter;
//transverse vector for output
for ( iter = info.begin(); iter != info.end(); ++iter)
{
/*for(int i = 0; i < nameCounter; i++)
{
erase(info.begin(), info.end(), info.end())
}*/
iter -> output_Names();
}//output
return 0;
}//main
And heres the error message:
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include/c++/v1/algorithm:658:97: Invalid operands to binary expression ('const Name_Sorter' and 'const Name_Sorter')
and where the error message links to:
template <class _T1>
struct __equal_to<_T1, _T1>
{
_LIBCPP_INLINE_VISIBILITY bool operator()(const _T1& __x, const _T1& __y) const {return __x == __y;}
};
Okay so I'm no longer getting the error message, however when I add in the operator== as suggested, the function seems to delete ALL duplicates from the vector, not just all duplicates except for one. If the input is "Hunter, Hunter, Hunter, Toby, Diane, Kiera" I wanted it to output "Diane, Hunter, Kiera, Toby" and for now it will just output "Diane, Kiera, Toby"
bool operator== (const Name_Sorter &t1, const Name_Sorter &t2)
{
return t1.name < t2.name;
}
Hopefully this can eventually help a lot more people trying to learn how to do this rather than just me.
Upvotes: 0
Views: 418
Reputation: 312
In my opinion , several things are strange :
Appart from that, since the vector is comped of custom elements, you need either to define the ==operand for your class or specifiying a third argument in the function unique which is your comp function. It's the same here --> std::unique and removing duplicates from a container of objects
I quickly rewrite some stuff for your code , and I don't get errors anymore. I guess it's not perfect but at least better
//class
class Name_Sorter
{
private:
//none
public:
Name_Sorter();
//~Name_Sorter();
std::string name;
void set_Names(std::string person_Name ){ name = person_Name; }
std::string get_Names(){ return name; }
void output_Names();
};
Name_Sorter::Name_Sorter() : name("")
{}
//get the user file
std::string get_File()//get input file
{
std::ifstream fin;
std::string file_To_Open;
std::cout << "What is the name of the file where you have stored the names? ";
getline(std::cin, file_To_Open);
//std::cout << file_To_Open; // for testing
return file_To_Open;
}
//output
void Name_Sorter::output_Names()
{
std::cout << "Name: " << name << std::endl;
}
//sort
bool comp(const Name_Sorter t1, const Name_Sorter t2) //definition
{
return t1.name == t2.name;
}//compare function
//main program
int main(int argc, const char * argv[])
{
//variables and vector
std::vector<Name_Sorter> info;
std::string names;
std::string file_To_Open;
std::ifstream fin;
int nameCounter = 0;
//get name
for(int i = 0 ; i < 5 ; i++)
{
Name_Sorter name_Data;
name_Data.set_Names("lolz");
info.push_back(name_Data);
nameCounter++;
}//get names
info.erase(std::unique(info.begin(), info.end() , comp) , info.end()) ;
for(auto i : info){
cout << i.get_Names() << endl;
}
return 0;
}//main
Upvotes: 0
Reputation: 10497
A quick suggestion based on what your code appears to do:
Name_Sorter
- it adds no value - replace it with simply with std::string
.std::vector
and use std::set
instead. It will automatically sort and weed out duplicates as each item is appended to it. There appears to be no reason you can't use it and it gets rid of all the de-duping / sorting code.Upvotes: 1
Reputation: 65620
std::unique
uses operator==
by default. You aren't passing a comparison function as you are in your call to std::sort
.
Either define a comparator and fix call to std::unique
, like this:
bool eqComp (const Name_Sorter &t1, const Name_Sorter &t2)
{
return t1.name == t2.name;
}
info.erase(std::unique(info.begin(), info.end(), eqComp), info.end());
// include comparator ^^^^
Or, even better, just overload operator==
for your type:
bool operator== (const Name_Sorter &t1, const Name_Sorter &t2)
{
return t1.name == t2.name;
}
info.erase(std::unique(info.begin(), info.end()), info.end());
Similarly, you can overload operator<
to make your std::sort
call simpler:
bool operator< (const Name_Sorter &t1, const Name_Sorter &t2)
{
return t1.name < t2.name;
}
std::sort(info.begin(), info.end());
Upvotes: 2
Reputation: 1292
std::unique requires operator== for compared types. Provide such an operator for your class, and it should work
Upvotes: -1
Reputation: 673
In Name_Sorter you need to define:
bool operator==(const Name_Sorter& a)
Upvotes: 0
Reputation: 1844
The best way to do so is by using vector, sort + unique as far as performance is concerned.
sort( vec.begin(), vec.end() );
vec.erase( unique( vec.begin(), vec.end() ), vec.end() );
Many other ways of doing the same can be found here
Upvotes: 0