Search code examples
c++vectordata-storage

How do you delete duplicate strings/data in a vector?


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.


Solution

  • 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());