Populate a vector with all multimap values with a given key

前端 未结 6 1668
伪装坚强ぢ
伪装坚强ぢ 2021-02-08 13:10

Given a multimap M what\'s a neat way to create a vector of all values in M with a specific key.

e.g given a multimap how c

相关标签:
6条回答
  • 2021-02-08 13:26

    Let's go lambda

    given: multimap<A,B> M

    requested: vector<B> (of all values in M with a specific key 'a'.)

    method:

    std::pair<M::iterator, M::iterator> aRange = M.equal_range('a')
    std::vector<B> aVector;
    std::transform(aRange.first, aRange.second,std::back_inserter(aVector), [](std::pair<A,B> element){return element.second;});         
    

    System environment:

    1. compiler: gcc (Ubuntu 5.3.1-14ubuntu2.1) 5.3.1 20160413 (with -std=c++11)
    2. os: ubuntu 16.04

    Code example:

    #include <algorithm>
    #include <vector>
    #include <map>
    #include <string>
    #include <functional>
    #include <iostream>
    
    int main()
    {
        typedef std::multimap<std::string, int> MapType;
        MapType m;
        std::vector<int> v;
    
        /// Test data
        for(int i = 0; i < 10; ++i)
        {
            m.insert(std::make_pair("123", i * 2));
            m.insert(std::make_pair("12", i));
        }
    
        std::pair<MapType::iterator,MapType::iterator> aRange = m.equal_range("123");
    
        std::transform(aRange.first, aRange.second, std::back_inserter(v), [](std::pair<std::string,int> element){return element.second;});
    
        for(auto & elem: v)
        {
            std::cout << elem << std::endl;
        }
        return 0;
    }
    
    0 讨论(0)
  • 2021-02-08 13:31

    Here's the way to do it STL style :

    // The following define is needed for select2nd with DinkumWare STL under VC++
    #define _HAS_TRADITIONAL_STL 1
    
    #include <algorithm>
    #include <vector>
    #include <map>
    #include <string>
    #include <functional>
    #include <map>
    #include <iterator>
    #include <iostream>
    
    using namespace std;
    
    void main()
    {
        typedef multimap<string, int> MapType;
        MapType m;
        vector<int> v;
    
        // Test data
        for(int i = 0; i < 10; ++i)
        {
            m.insert(make_pair("123", i * 2));
            m.insert(make_pair("12", i));
        }
    
        MapType::iterator i = m.lower_bound("123");
        MapType::iterator j = m.upper_bound("123");
    
        transform(i, j, back_inserter(v), select2nd<MapType::value_type>());
    
        copy(v.begin(), v.end(),  ostream_iterator<int>(cout, ","));
    
    }
    
    0 讨论(0)
  • 2021-02-08 13:35

    Just some addenda to the other answers here…

    std::mem_fn (from #include <functional>) can be used as a shorthand for the transform operator:

    // previously we might've used this longhand
    [](pair<int,string> element){return element.second;}
    

    And we can use vector::resize and std::distance to allocate space for the vector in one go, rather than repeatedly resizing it with back_inserter.

    #include <algorithm>
    #include <vector>
    #include <map>
    #include <string>
    #include <functional>
    #include <iterator>
    #include <iostream>
    
    using namespace std;
    
    typedef multimap<int, string> MapType;
    
    int main()
    {
        MapType multimap;
        vector<string> valuesForKey123;
    
        multimap.emplace(0,   "red");
        multimap.emplace(123, "hello");
        multimap.emplace(123, "world");
        multimap.emplace(0,   "herring");
    
        MapType::iterator lower{multimap.lower_bound(123)};
        MapType::iterator upper{multimap.upper_bound(123)};
        valuesForKey123.resize(distance(lower, upper));
    
        transform(
            lower,
            upper,
            valuesForKey123.begin(),
            mem_fn(&MapType::value_type::second));
    
        copy(
            valuesForKey123.begin(),
            valuesForKey123.end(),
            ostream_iterator<string>(cout, " "));
    }
    // outputs "hello world "
    
    0 讨论(0)
  • 2021-02-08 13:40

    You could initialise the vector by giving it two iterators, like this:

    std::multimap<std::string, std::string> bar;
    
    ...
    
    std::vector<pair<string,string> > foo(bar.lower_bound("123"), bar.upper_bound("123"));
    

    but that would give you a vector of pairs (ie, with both the key and value).

    Another option would be to use std::copy with something like a back_inserter, which is another way to hide the loop, but with the same downside as above.

    std::copy(bar.lower_bound("123"), bar.upper_bound("123"), std::back_inserter(foo));
    

    This would append the elements (if any) to the vector foo.

    For extracting the values only, I can't think of any way but to loop over the results as I'm not aware of a standard way to get only the value out of a range.

    0 讨论(0)
  • 2021-02-08 13:43

    You need a loop anyway. All "loop-free" methods just abstract the loop away.

    #include <map>
    #include <vector>
    #include <algorithm>
    #include <ext/functional>
    using namespace std;
    
    int main () {
        multimap<int, double> mm;
        mm.insert(make_pair(1, 2.2));
        mm.insert(make_pair(4, 2.6));
        mm.insert(make_pair(1, 9.1));
        mm.insert(make_pair(1, 3.1));
    
        vector<double> v;
        transform(mm.lower_bound(1), mm.upper_bound(1),
                  back_inserter(v), __gnu_cxx::select2nd<pair<int, double> >());
        // note: select2nd is an SGI extension.
    
        for (vector<double>::const_iterator cit = v.begin(); cit != v.end(); ++ cit)
            printf("%g, ", *cit);   // verify that you've got 2.2, 9.1, 3.1
        return 0;
    }
    
    0 讨论(0)
  • 2021-02-08 13:49
    template <class Key, class Val>
    vector<Val>& getValues(multimap<Key, Val>& multi, Key& key)
    {
        typedef multimap<Key, Val>::iterator imm;
        static vector<Val> vect;
        static struct 
        {
            void operator()(const pair<Key, Val>& p) const
            {
                vect.push_back(p.second);
            }
        } Push;
    
        vect.clear();
        pair<imm, imm> range = multi.equal_range(key);
        for_each(range.first, range.second, Push);
        return vect;
    }
    

    This is a bit contrived because of your 'no loop' requirement.

    I prefer:

    template <class Key, class Val>
    vector<Val> getValues(multimap<Key, Val>& map, Key& key)
    {
        vector<Val> result;
        typedef multimap<Key, Val>::iterator imm;
        pair<imm, imm> range = map.equal_range(key);
        for (imm i = range.first; i != range.second; ++i)
            result.push_back(i->second);
        return result;
    }
    
    0 讨论(0)
提交回复
热议问题