使用给定键的所有多重映射值填充向量

发布于 2024-08-27 16:54:24 字数 187 浏览 5 评论 0原文

给定一个 multimap M,这是一种使用特定键创建 M 中所有值的向量的巧妙方法。

例如,给定多重映射,我怎样才能获得映射到值 123 的所有字符串的向量?

答案很简单,从下限->上限循环,但是有没有一种简洁的无循环方法?

Given a multimap<A,B> M what's a neat way to create a vector<B> of all values in M with a specific key.

e.g given a multimap how can I get a vector of all strings mapped to the value 123?

An answer is easy, looping from lower->upper bound, but is there a neat loop-free method?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(7

懒猫 2024-09-03 16:54:25

无论如何,你需要一个循环。所有“无循环”方法只是将循环抽象出来。

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

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;
}
栖竹 2024-09-03 16:54:25
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;
}
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;
}
绳情 2024-09-03 16:54:25

您可以通过给定两个迭代器来初始化该向量,如下所示:

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 中。

为了仅提取值,我想不出任何方法,只能循环结果,因为我不知道仅获取范围之外的值的标准方法。

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.

故乡的云 2024-09-03 16:54:25

只是对这里其他答案的一些补充......

std::mem_fn(来自 #include)可以用作变换运算符的简写:

// 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 "

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 "
北笙凉宸 2024-09-03 16:54:25

要获取匹配元素,我们可以使用equal_range

在映射中,每个元素都是一对。在这种情况下,我们不能直接使用STL复制算法将匹配元素复制到向量中,因为我们不是直接复制元素(对),所以我们本质上要执行“映射”操作(使用函数式编程中的映射/过滤器术语),在 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

To get the matching elements we can use equal_range.

In a map, each element is a pair. In this case, we cannot directly use the STL copy algorithm to copy the matching elements into a vector since we are not copying the elements (pairs) directly, so we want to essentially perform a "mapping" operation (using the map/filter terminology from functional programming), which in C++ we can do using the transform algorithm:

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

Output:

v: c d
述情 2024-09-03 16:54:24

以下是 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, ","));

}

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

}
謌踐踏愛綪 2024-09-03 16:54:24

让我们使用 lambda

给定:multimap M

请求:vector(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)
  2. 操作系统: 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;
}

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;
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文