2008-10-29 74 views
31

Multimap基本上有按键排序的数据组。我想要一种方法,我可以访问这些单个组并获得它们的聚合值。 例如,在一个std::multimap< string, int >我存储stl :: multimap - 我如何获得数据组?

{"Group1", 1}, 
{"Group1", 2}, 
{"Group1", 3}, 

{"Group2", 10}, 
{"Group2", 11}, 
{"Group2", 12} 

具有存储这些值,我应该能够重复这种多重映射,并得到每一个“组”的合计值。问题是在STL中没有定义以这种方式访问​​MultiMaps的任何函数。我可以使用lower_bound,upper_bound来手动迭代multimap并总计组的内容,但我希望能在STL中定义更好的方法吗?任何人都可以提出一个解决方案,以了解如何在上面的示例中获得组的聚合值。

+0

非常优雅和这里描述的lambda方法: http://stackoverflow.com/a/37680747/5516759 – 2016-06-07 13:29:40

回答

38
pair<Iter, Iter> range = my_multimap.equal_range("Group1"); 
int total = accumulate(range.first, range.second, 0); 

是一种方式。

编辑:

如果你不知道你正在寻找的组,只是要通过每个组,获得下组的范围可以像这样做:

template <typename Pair> 
struct Less : public std::binary_function<Pair, Pair, bool> 
{ 
    bool operator()(const Pair &x, const Pair &y) const 
    { 
     return x.first < y.first; 
    } 
}; 

Iter first = mmap.begin(); 
Iter last = adjacent_find(first, mmap.end(), Less<MultimapType::value_type>()); 
+0

不应该是`x.first == y.first;`?你为什么使用`operator <`?根据`adjacent_find`的[document](http://www.cplusplus.com/reference/algorithm/adjacent_find/),谓词参数应该返回比较结果与真(非零),这意味着它们是被认为是相等的,并且假(零)不相等。为什么你返回不相等的结果是真的? – Meysam 2012-11-12 07:40:11

+2

是的,这似乎是一个错误。 `adjacent_find`需要一个“相等”的谓词。另外,我确定有`std :: equal_to `准备好使用。 – leemes 2013-01-03 15:08:59

10

如果您已经知道密钥,则可以使用multimap::equal_range将迭代器获取到组的开始和结束位置;使用任何标准算法从范围中获得所需的结果。如果您不知道密钥,您可以从begin()开始,并自己遍历它们,比较密钥以查找每个新组的开始。

-1

不是multimap答案,但如果您愿意,可以按照以下方式进行操作。

#include <iostream> 
#include <vector> 
#include <map> 
#include <string> 
#include <boost/assign/list_of.hpp> 
#include <boost/foreach.hpp> 
using namespace std; 
using namespace boost; 
using namespace boost::assign; 

int main() { 
    typedef map<string, vector<int> > collection; 
    collection m; 
    m["Group 1"] = list_of(1)(2)(3); 
    m["Group 2"] = list_of(10)(11)(12); 
    collection::iterator g2 = m.find("Group 2"); 
    if (g2 != m.end()) { 
     BOOST_FOREACH(int& i, g2->second) { 
      cout << i << "\n"; 
     } 
    } 
} 
1

您可以使用可以包含每个组的总和的备用容器。要做到这一点,你可以这样做:

template <class KeyType, class ValueType> 
struct group_add { 
    typedef map<KeyType, ValueType> map_type; 
    map_type & aggregates; 
    explicit group_add(map_type & aggregates_) 
    : aggregates(aggregates_) { }; 
    void operator() (map_type::value_type const & element) { 
    aggregates[element.first] += element.second; 
    }; 
}; 

template <class KeyType, class ValueType> 
group_add<KeyType, ValueType> 
make_group_adder(map<KeyType, ValueType> & map_) { 
    return group_add<KeyType, ValueType>(map_); 
}; 

// ... 
multimap<string, int> members; 
// populate members 
map<string, int> group_aggregates; 
for_each(members.begin(), members.end(), 
    make_group_adder(group_aggregates)); 
// group_aggregates now has the sums per group 

当然,如果你有LAMBDA的(C++ 0x中),也可以是简单的:

multimap<string, int> members; 
map<string, int> group_aggregates; 
for_each(members.begin(), members.end(), 
    [&group_aggregates](multimap<string, int>::value_type const & element) { 
    group_aggregates[element.first] += element.second; 
    } 
); 
19
// samekey.cpp -- Process groups with identical keys in a multimap 

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

typedef multimap<string, int> StringToIntMap; 
typedef StringToIntMap::iterator mapIter; 

int main() 
{ 
    StringToIntMap mymap; 

    mymap.insert(make_pair("Group2", 11)); 
    mymap.insert(make_pair("Group1", 3)); 
    mymap.insert(make_pair("Group2", 10)); 
    mymap.insert(make_pair("Group1", 1)); 
    mymap.insert(make_pair("Group2", 12)); 
    mymap.insert(make_pair("Group1", 2)); 

    cout << "mymap contains:" << endl; 

    mapIter m_it, s_it; 

    for (m_it = mymap.begin(); m_it != mymap.end(); m_it = s_it) 
    { 
     string theKey = (*m_it).first; 

     cout << endl; 
     cout << " key = '" << theKey << "'" << endl; 

     pair<mapIter, mapIter> keyRange = mymap.equal_range(theKey); 

     // Iterate over all map elements with key == theKey 

     for (s_it = keyRange.first; s_it != keyRange.second; ++s_it) 
     { 
      cout << " value = " << (*s_it).second << endl; 
     } 
    } 

    return 0; 

} // end main 

// end samekey.cpp 
0
equal_range 
Syntax:  
#include <map> 
pair<iterator, iterator> equal_range(const key_type& key); 
The function equal_range() returns two iterators - one to the first 
element that contains key, another to a point just after the last 
element that contains key.