AJ.
AJ.

Reputation: 2569

How can I get all the unique keys in a multimap

I have a multimap and I want get all the unique keys in it to be stored in a vector.

  multimap<char,int> mymm;
  multimap<char,int>::iterator it;
  char c;

  mymm.insert(pair<char,int>('x',50));
  mymm.insert(pair<char,int>('y',100));
  mymm.insert(pair<char,int>('y',150));
  mymm.insert(pair<char,int>('y',200));
  mymm.insert(pair<char,int>('z',250));
  mymm.insert(pair<char,int>('z',300));

How can I do this? there is way to count number of elements with a key but none to count number of unique keys in a multimap.

Added: By unique I mean all the keys in multimap once - they can be repeated or occur once in multimap.

So unique keys here are - x, y and z

Upvotes: 27

Views: 32110

Answers (7)

Catriel
Catriel

Reputation: 647

This can be done in O(N) where N is the size of your map; your keys do not need to have an order operator:

template<typename Container>
std::vector<typename Container::key_type> UniqueKeys (const Container &A)
{
std::vector<typename Container::key_type> v;
auto prevIter = A.begin ();

for (auto iter = A.begin (); iter != A.end(); ++iter)
    {
    if (prevIter->first == iter->first)
        continue;

    v.push_back (prevIter->first);
    prevIter = iter;
    }

if (prevIter != A.end ())
    v.push_back (prevIter->first);

return v;
}

Upvotes: 0

newandlost
newandlost

Reputation: 1020

Other option would be to insert them into a vector and then just use, std::sort and std::unique

template<typename Container> static
std::vector<typename Container::key_type> unique_keys(Container A)
{

    using ValueType = typename Container::key_type;

    std::vector<ValueType> v;

    for(auto ele : A)
    {
        v.push_back(ele.first);
    }

    std::sort(v.begin(), v.end());
    auto it = std::unique(v.begin(), v.end());
    v.resize(distance(v.begin(),it));

    return v;
}

Upvotes: 0

Gautam Jain
Gautam Jain

Reputation: 671

easiest way would be to put the keys of multimap in an unordered_set

unordered_multimap<string, string> m;

//insert data in multimap

unordered_set<string> s;         //set to store the unique keys

for(auto it = m.begin(); it != m.end(); it++){
    if(s.find(it->first) == s.end()){
        s.insert(it->first);
        auto its = m.equal_range(it->first);
        for(auto itr=its.first;itr!=its.second;itr++){
            cout<<itr->second<<" ";
        }
    }
}

Upvotes: 3

jogojapan
jogojapan

Reputation: 69967

Since the entries of a std::multimap<> are implicitly sorted and come out in sorted order when iterating through them, you can use the std::unique_copy algorithm for this:

#include <iostream>
#include <map>
#include <algorithm>
#include <vector>

using namespace std;

int main() {

  /* ...Your existing code... */

  /* Create vector of deduplicated entries: */
  vector<pair<char,int>> keys_dedup;
  unique_copy(begin(mymm),
              end(mymm),
              back_inserter(keys_dedup),
              [](const pair<char,int> &entry1,
                 const pair<char,int> &entry2) {
                   return (entry1.first == entry2.first);
               }
             );

  /* Print unique keys, just to confirm. */
  for (const auto &entry : keys_dedup)
    cout << entry.first << '\n';

  cout.flush();
  return 0;
}

The extra work added by this is linear in the number of entries of the multimap, whereas using a std::set or Jeeva's approach for deduplication both add O(n log n) computational steps.

Remark: The lambda expression I use assumes C++11. It is possible to rewrite this for C++03.

Upvotes: 18

Andrew
Andrew

Reputation: 24846

I think you can do something like this in case by unique you mean the key that is contained in the multimap only once:

1) construct a sorted list of all keys in your map

2) iterate over the list and find unique keys. It's simple since all duplicates will be near each other in a sorted container

If you want just all keys - use std::set as Donotalo suggested

Upvotes: 1

Jeeva
Jeeva

Reputation: 4663

I tried this and it worked

for(  multimap<char,int>::iterator it = mymm.begin(), end = mymm.end(); it != end; it = mymm.upper_bound(it->first))
  {
      cout << it->first << ' ' << it->second << endl;
  }

Upvotes: 50

Donotalo
Donotalo

Reputation: 13025

Iterate through all elements of mymm, and store it->first in a set<char>.

Upvotes: 9

Related Questions