C++ display map that has vector

馋奶兔 提交于 2019-12-25 07:59:00

问题


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

In order to print out this by using copy, how should my std::ostream_iterator be?

Apparently std::ostream_iterator<std::pair<std::string, std::vector<std::string>>> out_it(std::cout, "\n"); did not make it.

My operator<< overload is the following std::ostream& operator<<(std::ostream& out, const std::pair<std::string, std::vector<std::string>>& p) and it writes out the p.first and p.second and returns it.


回答1:


So here is a operator<< that will print out the contents of one pair from your map:

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

So to use it in this example. If you ennter this into your map:

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;

This would be what wil get printed out using the operator<< above:

KEY: VAL1, VAL2, VAL3, 

You can also change the formatting a bit so the comma isn't after the last value as well but that's only a cosmetic problem. Your problem was in that you wanted to print vector while it doesn't have std operator<<. So in order to print vector you must manually loop through it's content like in my example with the ranged for.




回答2:


If you do any serious programming in C++, you will eventually need a generic way to print out collections.

Here is the basis of one:

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

Expected output:

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



回答3:


To custom print your vector, you'd have to write some code yourself. To make sure your custom operator is used, I suggest you use std::stringstream to turn your key-value pair into a string, which you'd then feed into an std::ostream_iterator<std::string>.

Something, like this (pardon the 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;
}

I didn't actually write the operator<<, but you can substitue yours to make the lambda body short);



来源:https://stackoverflow.com/questions/41097518/c-display-map-that-has-vector

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!