1

I am trying to insert a few pairs of int into a set, these pairs don't have any order; that is, (1,2) = (2,1). So simply I do as follows,

typedef pair<int, int> pairs; 

set<pairs> Set;
pair <int,int> myPair;

// adding pairs:
myPair=pair<int,int>(0,1);
pathSet.insert(myPair);
myPair=pair<int,int>(0,2);
pathSet.insert(myPair);
myPair=pair<int,int>(1,0);
pathSet.insert(myPair);

So I end up a set like

(0,1), (0,2) , (1,0)

I want to have

(0,1), (0,2)

How can I avoid duplicate? Is there any way? Is there any better ADT like std::unordered_set in terms of efficiency in comparison with 'set'?

JeJo
  • 30,635
  • 6
  • 49
  • 88
Sarah
  • 133
  • 11
  • 2
    I recommend [this `std::set` reference](https://en.cppreference.com/w/cpp/container/set), and that you learn about custom [compare](https://en.cppreference.com/w/cpp/named_req/Compare) functions. – Some programmer dude Jun 24 '18 at 19:00
  • Thanks for links. But I dont get what is wrong if someone doesnt know something and ask here? why should others give a negative score? perhaps I couldnt find it and didnt know where to start that asked it here! its so unfair and disappointing! @Someprogrammerdude – Sarah Jun 24 '18 at 19:09
  • It is expected that posters do some research, like finding a reference such as the one I linked to, and seeing the possible comparator arguments and then try to use it and if not working asking a question about how to use it. Unfortunately some people sees all newbie questions as not enough research and votes down. Even if you have [a good question](http://stackoverflow.com/help/how-to-ask) and followed [a good question checklist](https://codeblog.jonskeet.uk/2012/11/24/stack-overflow-question-checklist/) you still have the risk of downvotes. – Some programmer dude Jun 24 '18 at 19:19

2 Answers2

2

You'll need a custom comparison function. In there, make sure that the order of the elements in a pair do not matter when comparing. A simple way would be to let the first element in the pair always be the smaller one (and exchange first and second otherwise).

The code could look like as follows:

int main() {

    typedef pair<int, int> pairs;

    auto cmp = [](pairs a, pairs b) {
        if (a.first > a.second) {
            swap(a.first, a.second);
        }
        if (b.first > b.second) {
            swap(b.first, b.second);
        }
        return a < b;
    };
    set<pairs, decltype(cmp)> pathSet(cmp);

    pairs myPair=pair<int,int>(0,1);
    pathSet.insert(myPair);
    myPair=pair<int,int>(0,2);
    pathSet.insert(myPair);
    myPair=pair<int,int>(1,0);
    pathSet.insert(myPair);

    cout << pathSet.size();
}

Output:

2
Stephan Lechner
  • 34,891
  • 4
  • 35
  • 58
1

You need a custom compare function for std::set as you are using a std::pair as template type. In C++11, you can make it as a lambda as well.

The idea of compare function is to first check if the Pair is Pair.first < Pair.second, if not, swap to make them in order inside the compare function. This will not change the order of original inserted pair elements, but remove the duplicates as you mentioned.

auto compare = [](pairs lhs, pairs rhs) 
   {
      if(lhs.first > lhs.second ) lhs = pairs{lhs.second, lhs.first };
      if(rhs.first > rhs.second ) rhs = pairs{rhs.second, rhs.first };
      return lhs< rhs;
   };

Something like this: See live here

#include <iostream>
#include <set>

typedef std::pair<int, int> pairs;

int main()
{
   auto compare = [](pairs lhs, pairs rhs) //custom compare lambda function
   {
      if(lhs.first > lhs.second ) lhs = pairs{lhs.second, lhs.first };
      if(rhs.first > rhs.second ) rhs = pairs{rhs.second, rhs.first };
      return lhs< rhs;
   };

   std::set<pairs, decltype(compare)> Set(compare);

   Set.emplace(std::make_pair(0,1)); // use can also emplace to the Set
   Set.emplace(pairs{0,2});
   Set.emplace(pairs{1,0});

   for(const auto& it: Set)
      std::cout << it.first << " " << it.second << std::endl;
}

Output:

0 1
0 2
JeJo
  • 30,635
  • 6
  • 49
  • 88