std::map with std::pair keys where pair elements has no order importance

≡放荡痞女 提交于 2020-01-14 01:44:18

问题


As the question says, I need to use std::map in such way that.

std::map<std::pair<int, int>, int*> m;

int* a_ptr = new int;
*a_ptr = 15;
m[std::make_pair(1, 2)] = a_ptr;
std::cout << *m[std::make_pair(2, 1)] << std::endl; //should output 15

Now, in my actual implementation all the keys and values are actually pointers. How should I approach this problem?

Two ideas come to my mind.

  1. One is I should write a function that every time I am using m[] to access or to write into map, I should also m.find() check the other pair combination and act according to that.

  2. Other is using std::unordered_map with a custom hasher that somehow makes no difference when pair's elements positions are switched. (I have no idea how to do this, if I multiply or add the two pointers the result won't be equal. Need some help if this is the way to go.)

If you can think a better method I will be glad to hear it, otherwise I have stated what I need help with in the second clause. (which I think is more efficient, first one does not look good)

Thanks.


回答1:


Could you simply ensure the pairs are always in the same order? Use a helper function, like:

std::pair<int,int> my_make_pair(int a, int b) 
{
    if ( a < b ) return std::pair<int,int>(a,b);
    else return std::pair<int,int>(b,a);
}

and always use it to access the map:

m[my_make_pair(1,2)] = a_ptr;
std::cout << m[my_make_pair(2, 1)] << std::endl;



回答2:


Just use a custom comparator

[](std::pair<int, int> const& lhs, std::pair<int, int> const& rhs) {
   int lhs_min = std::min(lhs.first, lhs.second);
   int lhs_max = std::max(lhs.first, lhs.second);
   int rhs_min = std::min(rhs.first, rhs.second);
   int rhs_max = std::max(rhs.first, rhs.second);

   return lhs_min < rhs_min || (!(rhs_min < lhs_min) && lhs_max < rhs_max)
}

How does this work?

The first few lines deterministically order the 2 elements of a pair; that is, you can supply them in either order and lhs_min & lhs_max will be the same. We then use a standard equivalence technique for the result. All integer copies will be optimised out by the compiler and min/max will be inlined.

Note that I used C++11's lambdas for convenience of typing and have since discovered that there is no nice way of using them as the comparator for a std::map, so you would have to write a functor proper.




回答3:


template<typename T, typename PairCmp = std::less<std::pair<T,T>> >
struct symmetric_pair_sort {
  bool operator()( std::pair<T,T> const& left, std::pair<T,T> const& right ) const {
    if (left.second<left.first) {
      return (*this)(std::make_pair( left.second, left.first ), right );
    }
    if (right.second<right.first) {
      return (*this)(left, std::make_pair( right.second, right.first ) );
    }
    return PairCmp()(left, right);
  }
};

// or, the far bulkier yet more efficient:
template<typename T, typename PairCmp = std::less<std::pair<T&, T&>> >
struct symmetric_pair_sort {
  template<bool left_reversed, bool right_reversed>
  bool Helper( std::pair<T,T> const& left, std::pair<T,T> const& right ) const {
    std::pair<T&, T&> left_ordered( left_reversed?left.first:left.second, left_reversed?left.second:left.first );
    std::pair<T&, T&> right_ordered( right_reversed?right.first:right.second, right_reversed?right.second:right.first );
    return PairCmp()( left_ordered, right_ordered );
  }
  bool operator()( std::pair<T,T> const& left, std::pair<T,T> const& right ) const {
    if (left.second<left.first) {
      if (right.second<right.first) {
        return Helper<true, true>(left, right);
      } else {
        return Helper<true, false>(left, right);
      }
    } else {
      if (right.second<right.first) {
        return Helper<false, true>(left, right);
      } else {
        return Helper<false, false>(left, right);
      }
  }
};

std::map<std::pair<int, int>, int*, symmetric_pair_sort<int> > m;



回答4:


An alternative solution is to use std::set<int> instead of std::pair<int,int>. Sets store their data ordered, hence there is no need to order your pair, so precisely fulfill your requirement.

On the other hand, the other answers to use a compare wrapper around pair that explicitly orders the pairs might be more practical.



来源:https://stackoverflow.com/questions/15420086/stdmap-with-stdpair-keys-where-pair-elements-has-no-order-importance

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!