c++ 用给定键的所有多重Map值填充向量

cdmah0mi  于 2023-05-24  发布在  其他
关注(0)|答案(7)|浏览(283)

给定一个multimap<A,B> M,用一个特定的键创建一个包含M中所有值的vector<B>的简洁方法是什么?
例如,给定一个multimap,我如何得到所有Map到值123的字符串的向量?

  • An* 的答案很简单,从lower->upper bound循环,但是否有一个简洁的无循环方法?
dwbf0jvd

dwbf0jvd1#

下面是STL风格的实现方法:

// 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, ","));

}
7jmck4yq

7jmck4yq2#

让我们用lambda

给定:multimap<A,B> M
requested:vector<B>(M中所有值的一个特定键'a'。
方法:

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;});

系统环境:
1.编译器:gcc(Ubuntu 5.3.1-14ubuntu2.1)5.3.1 20160413(with -std=c++11)
1.操作系统:ubuntu 16.04
代码示例:

#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;
}
l2osamch

l2osamch3#

反正你需要一个循环。所有的“无循环”方法都只是将循环抽象出来。

#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;
}
yzxexxkh

yzxexxkh4#

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;
}

这是一个有点做作,因为你的'无循环'的要求。
我更喜欢:

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;
}
4ioopgfo

4ioopgfo5#

你可以通过给它两个迭代器来初始化向量,像这样:

std::multimap<std::string, std::string> bar;

...

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

但这将给予你一个向量对(即,与键和值)。
另一种选择是使用std::copy和类似back_inserter的东西,这是另一种隐藏循环的方法,但缺点与上面相同。

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

这将把元素(如果有的话)附加到向量foo。
对于只提取值,我想不出任何方法,但循环结果,因为我不知道一个标准的方法来获得一个范围外的值。

erhoui1w

erhoui1w6#

只是对其他答案的一些补充...
std::mem_fn(来自#include <functional>)可以用作变换运算符的简写:

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

我们可以使用vector::resizestd::distance一次性为向量分配空间,而不是使用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 "
jq6vz3qz

jq6vz3qz7#

为了得到匹配的元素,我们可以使用equal_range
在Map中,每个元素都是一对。在这种情况下,我们不能直接使用STL copy算法将匹配的元素复制到向量中,因为我们没有直接复制元素(对),所以我们希望本质上执行“Map”操作(使用函数式编程中的map/filter术语),在C++中我们可以使用transform算法来执行:

#include <iostream>
#include <map>                  // for multimap
#include <vector>
#include <algorithm>            // for transform
using namespace std;

int main() {
    multimap<int, string> m = {
        {1, "a"},
        {1, "b"},
        {123, "c"},
        {123, "d"},
        {2, "e"}
    };

    vector<string> v;
    auto [begin, end] = m.equal_range(123);
    transform(begin, end, back_inserter(v), [](const pair<int, string>& p) {
        return p.second;
    });

    cout << "v: ";
    for (auto& x : v) cout << x << " ";
}

输出:

v: c d

相关问题