0

Using Cmp I'm sorting the multiset by a second value of a pair.

Problem 1: I did not used set because I can't store both {5,3} and {6,3} and I don't know why since they are different.

using pair_type = std::pair<int, int>;

struct Cmp
{
    bool operator()(const pair_type& v1, const pair_type& v2) const
    { 
        return v1.second < v2.second; 
    }
};

int main()
{
multiset<pair_type,Cmp> m;

    m.insert({1,1});
    m.insert({2,1});
    m.insert({3,2});
    m.insert({4,2});
    m.insert({5,3});
    m.insert({6,3});

    auto itr = m.find({6,3});

    m.erase(itr);
}

Problem 2: Also m.erase erases {5,3} instead of {6,3} i.e first pair with same second value is erased. In fact m.find({6,3}) returns {5,3}. What causes this and how to solve these two problems?

Hansie
  • 39
  • 7
  • Note that using multimap doesn't solve your issue - it just hide it in certain circumstances. – Mike Vine Dec 30 '19 at 10:29
  • @MikeVine How to sort multimap automatically by value ? – Hansie Dec 30 '19 at 10:45
  • @MikeVine You are right – Hansie Dec 30 '19 at 10:51
  • 1
    _I did not used `set` because I can't store both `{5,3}` and `{6,3}` and I don't know why since they are different._ — From the perspective of `std::set` with `Cmp` comparator, they are **not different**. The only way `std::set` can test equality is to use `Cmp`. Note this quote from [cppreference/set](https://en.cppreference.com/w/cpp/container/set): _In imprecise terms, two objects `a` and `b` are considered equivalent if neither compares less than the other._ – Daniel Langr Dec 30 '19 at 11:08
  • Your comparator tells it that {5,3} and {6,3} are *the same thing*. Are you surprised that when you search for {6,3}, you get {5,3} which is the same as what you searched for? – user253751 Dec 30 '19 at 12:59

2 Answers2

1

You are explicitly only comparing the second value for pair in your cmp:

 return v1.second < v2.second;

You need to compare both:

 return v1 < v2;

Or just don't add a comparator at all.

If you don't do this, then a find will find any item with value {xxx, 3} which is what you're seeing. If you make this change, you can use a set instead as the values will compare differently.

A more technical explanation: When you provide a custom comparator which only compares using the second value in a pair then the container cannot differentiate between {5, 3} and {6, 3} - you have explicitely told it that they are the same, and so searching/equality will not work as you want.

Mike Vine
  • 9,468
  • 25
  • 44
  • The work i am doing involves sorting by second element of pair . – Hansie Dec 30 '19 at 10:25
  • @Hansie Usually you should not/do not care about which element you sort - if you are doing inserts/finds then sorting order doesn't matter. If you are iterating over the whole map (or subsets therein) then ordering does admittedly matter. In that case either keep using the default sort but swap your values, or just use the reverse of the normal sort: return lhs.second – Mike Vine Dec 30 '19 at 10:28
  • I need to get first element of multiset sometimes and thus i need to sort it . I may also update elements of multiset. – Hansie Dec 30 '19 at 10:36
  • something like this will solve your issue: {if(v1.second == v2.second) return v1.first – cosmos Dec 30 '19 at 10:37
  • above will sort by second value, if second value is equal will sort by first value.. – cosmos Dec 30 '19 at 10:38
0

I did not used set because I can't store both {5,3} and {6,3} and I don't know why since they are different.

You told the set they were the same. Because they are the same, it didn't store both, because it only stores one of each thing.

Problem 2: Also m.erase erases {5,3} instead of {6,3} i.e first pair with same second value is erased.

That's because m.find finds {5,3} and then you erase the item which it finds.

In fact m.find({6,3}) returns {5,3}. What causes this and how to solve these two problems?

Well, you told it that {5,3} and {6,3} are the same thing. You searched for a value, and it found a value that is equal to the one you searched for. That's what searching does.

If you want it to not treat these values as the same, then you need to use a comparator which does not say they are the same.

From the multiset's point of view, you have inserted a 3, another 3, then you have searched for 3, and you are complaining that it has found the first 3 instead of the second 3. How was it supposed to know you wanted the second one?

user253751
  • 57,427
  • 7
  • 48
  • 90