1

I have two multimaps.i would like to create a new multimap which has the common key-value pairs in the given those two multimaps:

for eg:

#include <iostream>
#include <string>
#include <map>
using namespace std;

int main ()
{


multimap<std::string, std::string> m;
multimap<std::string, std::string> n;


m.insert(multimap<string,string>::value_type("1-2","1-1"));
m.insert(multimap<string,string>::value_type("1-2","1-2"));
m.insert(multimap<string,string>::value_type("1-2","1-3"));
m.insert(multimap<string,string>::value_type("1-2","1-4"));
m.insert(multimap<string,string>::value_type("1-3","2-1"));
m.insert(multimap<string,string>::value_type("1-3","21-1"));
m.insert(multimap<string,string>::value_type("1-3","21-2"));

n.insert(multimap<string,string>::value_type("1-2","1-1"));
n.insert(multimap<string,string>::value_type("1-2","1-2"));
n.insert(multimap<string,string>::value_type("1-2","1-5"));
n.insert(multimap<string,string>::value_type("1-2","1-7"));
n.insert(multimap<string,string>::value_type("1-3","2-1"));
n.insert(multimap<string,string>::value_type("1-3","21-4"));
n.insert(multimap<string,string>::value_type("1-3","21-2"));

cout<<"multimap of m"<<endl;
cout<<"--------------"<<endl;
for(multimap<string,string>::iterator i=m.begin();i!=m.end();i++)
cout <<i->first<<" "<<i->second<<endl;
cout<<"multimap of n"<<endl;
cout<<"--------------"<<endl;
for(multimap<string,string>::iterator i=n.begin();i!=n.end();i++)
cout <<i->first<<" "<<i->second<<endl;

}

this results in :

multimap of m
--------------
1-2 1-1
1-2 1-2
1-2 1-3
1-2 1-4
1-3 2-1
1-3 21-1
1-3 21-2
multimap of n
--------------
1-2 1-1
1-2 1-2
1-2 1-5
1-2 1-7
1-3 2-1
1-3 21-4
1-3 21-2

i want to create a new multimap: which has the below elements:

1-2 1-1
1-2 1-2
1-3 2-1
1-3 21-2

EDIT:

also is there a way where i can delete the common elements( pair) from both the maps.

Vijay
  • 65,327
  • 90
  • 227
  • 319

3 Answers3

5

Use the std::set_intersection function template from <algorithm>

std::multimap<T1, T2> newMap;
std::set_intersection(map1.begin(), map1.end(), 
                      map2.begin(), map2.end(), 
                      std::inserter(newMap, newMap.begin());

Edit Yeah, apparently this doesn't work for a multimap as it would for a map. I suggest the following:

std::multimap<T1, T2> newMap;
std::vector<std::multimap<T1, T2>::value_type> v1(map1.begin(), map1.end());
std::sort(v1.begin(), v1.end());
std::vector<std::multimap<T1, T2>::value_type> v2(map2.begin(), map2.end());
std::sort(v2.begin(), v2.end());
std::set_intersection(v1.begin(), v1.end(), 
                      v2.begin(), v2.end(), 
                      std::inserter(newMap, newMap.begin());
Armen Tsirunyan
  • 130,161
  • 59
  • 324
  • 434
  • 1
    I ran this (built using VS2010) and it fails to include `1-3 21-2`. If I swap the insertion of `1-3 21-4` and `1-3 21-2` into `n` then it produces the correct result. – hmjd Dec 19 '11 at 10:31
  • 1
    I think set_intersection needs the stl's to be sorted before they pass onto it. – Vijay Dec 19 '11 at 10:42
  • 1
    @RahulDravid, and for `multimap` the following is stated: "The order of the key-value pairs whose keys compare equivalent is the order of insertion and does not change." – hmjd Dec 19 '11 at 10:46
  • 1
    Yeah so this means that set_intersection does not work in this case!! since i can have unsorted data in the value's – Vijay Dec 19 '11 at 10:52
  • Yeah ...you are right..but i am a bit concerned about the time it will take sort.nyways i will try it.Also is there a way that i delete the common elements from both the maps? – Vijay Dec 19 '11 at 10:57
  • @RahulDravid: Yes, calculate the intersection, and then use set_difference to get the elements that are not common – Armen Tsirunyan Dec 19 '11 at 11:14
3

As an alternative solution to Armen's (which is excellent), here's a way to copy and sort at the same time:

typedef std::multimap<std::string, std::string> map_type;
map_type m, n, result;

m.insert(std::make_pair("1-2", "1-1"));
// --------8<--------
n.insert(std::make_pair("1-3", "21-2"));

// --------8<--------    

std::set<map_type::value_type> s1(m.begin(), m.end());
std::set<map_type::value_type> s2(n.begin(), n.end());
std::set_intersection(s1.begin(), s1.end(), 
                      s2.begin(), s2.end(), 
                      std::inserter(result, result.end()));

Output:

intersection
============
1-2 1-1
1-2 1-2
1-3 2-1
1-3 21-2

To get the elements that are only in m:

result.clear();
std::set_difference(s1.begin(), s1.end(), 
                    s2.begin(), s2.end(), 
                    std::inserter(result, result.end()));

And only in n:

result.clear();
std::set_difference(s2.begin(), s2.end(), 
                    s1.begin(), s1.end(), 
                    std::inserter(result, result.end()));

See it run.

Since you've copied m and n (into s1 and s2) at the time of doing the set_difference(), you could clear() these and insert into them instead of result.

Community
  • 1
  • 1
johnsyweb
  • 136,902
  • 23
  • 188
  • 247
  • 1
    +1: Didn't think of the set. Although to be honest I really have no idea whether one way or another will be considerably faster. Let the OP try that one out – Armen Tsirunyan Dec 19 '11 at 11:16
0

For fun, here's the direct algorithm, which moves common elements into a new multimap, changing the original maps. You will recognize the standard "set intersection" algorithm for sorted ranges on the outer loop (concerning first); and since we cannot assume anything about the mapped values, the inner loop (concerning second) is a linear search over the mapped values to find equals.

template <typename T>
T move_common(T & a, T & b)
{
  typename T::const_iterator it1 = a.cbegin(), iend = a.cend(), jt1 = b.cbegin(), jend = b.cend();

  T result;

  while (it1 != iend && jt1 != jend)
  {
    if (it1->first < jt1->first)
    {
      ++it1;
    }
    else if (jt1->first < it1->first)
    {
      ++jt1;
    }
    else
    {
      typename T::const_iterator it2 = it1;

      while (it2 != iend && it2->first == it1->first)
      {
        typename T::const_iterator jt2 = jt1;
        while (jt2 != jend && jt2->first == jt1->first)
        {
          if (jt2->second == it2->second)
          {
            result.insert(*it2);
            if (it2 == it1) { a.erase(it1++); it2 = it1; } else { a.erase(it2++); }
            if (jt2 == jt1) { b.erase(jt1++); } else { b.erase(jt2); }
            break;
          }
          else
          {
            ++jt2;
            if (jt2 == jend || jt2->first != jt1->first) { ++it2; break; }
          }
        }
      }
      it1 = it2;
    }
  }
  return result;
}

Result:

common  = [(1-2, 1-1), (1-2, 1-2), (1-3, 2-1), (1-3, 21-2)]
n after = [(1-2, 1-3), (1-2, 1-4), (1-3, 21-1)]
m after = [(1-2, 1-5), (1-2, 1-7), (1-3, 21-4)]
Kerrek SB
  • 464,522
  • 92
  • 875
  • 1,084