【问题标题】:C++ display map that has vector具有矢量的 C++ 显示地图
【发布时间】:2016-12-12 09:17:58
【问题描述】:

std::map<std::string, std::vector<string>> data;

为了使用copy 打印出来,我的std::ostream_iterator 应该是什么?

显然std::ostream_iterator<std::pair<std::string, std::vector<std::string>>> out_it(std::cout, "\n"); 没有成功。

我的operator<< 重载是以下std::ostream& operator<<(std::ostream& out, const std::pair<std::string, std::vector<std::string>>& p),它写出p.firstp.second 并返回它。

【问题讨论】:

  • 弄清楚 A) 如何“显示”一个简单的向量。 B)如何显示一个简单的地图,例如map<string, int>。然后结合这两个知识。
  • 请提供完整的代码示例,说明您的整个操作符
  • @juanchopanza 你的意思是我需要使用for循环?因为要显示地图,它是std::ostream_iterator<std::pair<std::string, int>> ...
  • 你重载的operator<<不太可能被std::ostream_iterator使用
  • 如果在你的程序中有意义的话,你可以把任何你想要的东西放到地图中,为什么不呢。

标签: c++ string vector std-pair


【解决方案1】:

如果您使用 C++ 进行任何认真的编程,您最终将需要一种通用的方式来打印出集合。

这是一个基础:

#include <iostream>
#include <map>
#include <vector>
#include <string>


// introduce the concept of an object that emits values to an ostream
// by default it simply calls operator <<
template<class T> struct emitter
{
    using arg_type = T;

    emitter(const T& v) : v_(v) {}

    friend std::ostream& operator<<(std::ostream& os, const emitter& e) {
        return os << e.v_;
    }

    const T& v_;
};

// introduce the concept of an io manipulator called emit
template<class T> auto emit(const T& v) -> emitter<T>
{
    return emitter<std::decay_t<T>>(v);
}

// specialise the emitter for maps
template<class K, class V, class C, class A>
struct emitter<std::map<K, V, C, A>>
{
    using arg_type = std::map<K, V, C, A>;

    emitter(const arg_type& v) : v_(v) {}

    friend std::ostream& operator<<(std::ostream& os, const emitter& e) {
        const char* elem_sep = "\n\t";
        const char* end_sep = " ";
        os << "{";
        for (const auto& elem : e.v_)
        {
            os << elem_sep << emit(elem.first) << ": " << emit(elem.second);
            end_sep = "\n";
        }

        return os << end_sep << "}";
    }

    const arg_type& v_;
};

// specialise the emitter for vectors
template<class V, class A>
struct emitter<std::vector<V, A>>
{
    using arg_type = std::vector<V, A>;

    emitter(const arg_type& v) : v_(v) {}

    friend std::ostream& operator<<(std::ostream& os, const emitter& e) {
        const char* elem_sep = " ";
        const char* end_sep = " ";
        os << "[";
        for (const auto& elem : e.v_)
        {
            os << elem_sep << emit(elem);
            elem_sep = ", ";
        }

        return os << end_sep << "]";
    }

    const arg_type& v_;
};


int main() {
    // build test data
    std::map<std::string, std::vector<std::string>> data;

    data.emplace("a", std::vector<std::string>{ "now", "is", "the", "time" });
    data.emplace("b", std::vector<std::string>{ "for", "all", "good", "men" });
    data.emplace("c", std::vector<std::string>{ "to", "come", "to", "the" });
    data.emplace("d", std::vector<std::string>{ "aid", "of", "their", "party" });

    // request an emitter manipulator
    std::cout << emit(data) << std::endl;
}

预期输出:

{
    a: [ now, is, the, time ]
    b: [ for, all, good, men ]
    c: [ to, come, to, the ]
    d: [ aid, of, their, party ]
}

【讨论】:

  • 这是一个非常有用的答案。虽然我觉得比作者的问题要高一点。
  • @MarošBeťko 我不认为 c++ 是一个基于关卡的游戏。俗话说,“你不能有点怀孕”;-)
  • @RichardHodges 感谢您的宝贵意见。我还处于新手级别,这只是我在我的课程中还没有遇到过的东西,但我相信它将来会很好用!再次感谢您!
  • @user3221454 看看你能不能理解它对你有好处。领先于曲线永远不会受到伤害。祝你学习顺利。
【解决方案2】:

所以这是一个operator&lt;&lt;,它将从您的地图中打印出一对的内容:

std::ostream& operator<<(std::ostream& out, const std::pair<std::string, std::vector<std::string>>& p) {
    out << p.first << ": "; // prints the string from key
    for (const auto& i : p.second) // loops throught the whole vector that is asociated with that key
        out << i << ", ";
    return out;
}

所以在这个例子中使用它。如果您将其输入到地图中:

std::map<std::string, std::vector<string>> data;
std::vector<std::string> vec = {"VAL1", "VAL2", "VAL3"};
data.insert(std::make_pair("KEY", vec));
auto it = data.find("KEY");
std::cout << *it;

这将是使用上面的运算符

KEY: VAL1, VAL2, VAL3, 

您还可以稍微更改格式,以便逗号不在最后一个值之后,但这只是一个外观问题。你的问题是你想打印向量,而它没有标准运算符

【讨论】:

  • 谢谢,您的回答对我来说是最清楚的。这对我来说很容易理解并且与我的练习相关。您的 operator&lt;&lt; 非常适合我的情况,非常感谢!
【解决方案3】:

要自定义打印矢量,您必须自己编写一些代码。为确保使用您的自定义运算符,我建议您使用 std::stringstream 将您的键值对转换为字符串,然后将其输入到 std::ostream_iterator&lt;std::string&gt;

一些东西,比如this(请原谅using namespace std;):

#include <iostream>
#include <vector>
#include <string>
#include <iterator>
#include <algorithm>
#include <sstream>
#include <map>

using namespace std;

int main() {
    map<string, vector<string>> m {
        {"a", {"1", "2"}},
        {"b", {"1", "2"}},
        {"b", {"1", "2"}},
    };

    transform(begin(m), end(m), ostream_iterator<string>(cout), [](auto& p){
        stringstream ss;
        ss << p.first << ", {";
        bool first = true;
        for (auto& s : p.second)
        {
          ss << (first ? "" : ", ") << s;
          first = false;
        }
        ss << "}\n";
        return ss.str();
    });

    return 0;
}

operator&lt;&lt; 实际上并不是我写的,但你可以用你的来代替你的 lambda 主体);

【讨论】:

    猜你喜欢
    • 2016-07-13
    • 2021-02-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-10-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多