1

std::set<std::string> &uniq_email_list;

I have a set of many email elements, for examples:

('[email protected]', '[email protected]', '[email protected]', '[email protected]','[email protected]')

then I write these elements to a file

for(iter = uniq_email_list.begin() ; iter!=uniq_email_list.end(); ++iter){  
            output_file<< *iter << std::endl;
        }

Before I write these elements to the file, I want to sort by '@' next domain name and I want it to look like this in the file

[email protected]
[email protected]
[email protected]
[email protected]
[email protected]

And I know

You cannot resort a set, how it sorts is part of the type of the particular set. A given set has a fixed set order that cannot be changed.

You could create a new set with the same data relatively easily. Just create a new set that sorts based on the new criteria

I read that post Sorting Sets using std::sort But I couldn't find the answer to my problem.

As a result of my research I found something like

std::set<string>::iterator &it;
it=myset.find('@');

Can I sort by the returned address with this structure? Or if there are other solutions suitable for this problem, thank you in advance, I am ready to get advice on issues related to C ++ solutions.

testerenecmi
  • 34
  • 1
  • 8
  • Please do not use "C/C++". C and C++ are very different languages. What you show is clearly no C. – Gerhardh Jan 29 '21 at 12:06
  • What does "this structure" mean? No, a `std::set` cannot be sorted, no matter what other structures exist in the code. – Sam Varshavchik Jan 29 '21 at 12:13
  • You can set custom comparator to `std::set`. [std::set::set - cppreference.com](https://en.cppreference.com/w/cpp/container/set/set) – MikeCAT Jan 29 '21 at 12:17

2 Answers2

4

If you are going to use the domain and name parts individually, I suggest that you split them up and put them in an email class for which you provide an operator< that fulfills the Compare requirement needed to create a std::set<email>:

#include <tuple>  // std::tie

struct email {
    std::string name;
    std::string domain;

    // The compare operator used by default by a std::set<email>:
    bool operator<(const email& rhs) const {

        // using std::tie makes creating an operator< that does
        // strict weak ordering relatively easy:

        return std::tie(domain, name) < std::tie(rhs.domain, rhs.name);
    }
};

std::ostream& operator<<(std::ostream& os, const email& e) {
    os << e.name;
    if(not e.domain.empty()) os << '@' << e.domain;
    return os;
}

std::istream& operator>>(std::istream& is, email& e) {
    if(std::string tmp; is >> tmp) {

        auto at_pos = tmp.find('@');        
        e.name = tmp.substr(0, at_pos);

        if(at_pos != std::string::npos) {    
            e.domain = tmp.substr(at_pos + 1);
        } else {
            e.domain.clear();
        }
    }
    return is;
}

You can now put them in a std::set<email> or in a std::vector<email> (and std::sort that vector) and stream them out in the order specified by the member operator<. Domain first, name last and also read from streams:

email tmp;
while(instream >> tmp) {
    std::cout << "read address: " << tmp << '\n';
}

Demo

Ted Lyngmo
  • 93,841
  • 5
  • 60
  • 108
2
class EmailCompare
{
public:
    bool operator()(const std::string& a, const std::string& b) const {
        // your code here
        return ... ;
    }
};

using EmailSet = std::set<std::string, EmailCompare>;
acraig5075
  • 10,588
  • 3
  • 31
  • 50
Marek R
  • 32,568
  • 6
  • 55
  • 140