我正在使用如下所示的数据结构:
map<string, set<string>> data;
到目前为止,我使用foreach循环处理地图没有任何问题,但是,现在我需要打印出地图中的数据,如下所示:
KEY: elem1, elem2, elem3
KEY2: elem1, elem2, elem3
由于最后缺少逗号,我不能再使用foreach循环了(我可以吗?)。由于我是C ++,C ++ 11以及它提供的所有乐趣的新手,我很遗憾。 我提出了:
for ( auto i : data )
{
cout << i.first << ": ";
for ( size_t i = 0; i < /* size of the set */ - 1; i ++ )
cout << j << ", ";
cout << /* the last element of the set */ << endl;
}
我知道我想要什么,我只是不知道语法,而且C ++参考没有多大帮助。 感谢您的回答,同时我将自己浏览C ++参考。
答案 0 :(得分:4)
我经常使用的模式(BOOST_FOREACH
)是:
bool first = true;
for (auto const& e: collection) {
if (first) { first = false; } else { out << ", "; }
...
}
使用ostream_iterator
:
std::copy(collection.begin(), collection.end(),
std::ostream_iterator<value_type>(out, ", "));
所以你的例子变成了:
for (auto const& pair: map) {
out << pair.first << ": ";
std::copy(pair.second.begin(), pair.second.end(),
std::ostream_iterator<std::string>(out, ", "));
}
但老实说,我仍然觉得使用bool first = true
方法更具可读性。
答案 1 :(得分:2)
我通常(跨多种语言)使用分隔符,我将其初始化为空字符串,然后在循环中更改:
for (auto& i : data) {
std::cout << i.first << ": ";
std::string delim;
for (auto& s : i.second) {
std::cout << delim << s;
delim = ", ";
}
std::cout << std::endl;
}
KEY: elem1, elem2, elem3
KEY1: elem1, elem2, elem3
答案 2 :(得分:2)
您可以考虑这样的代码(使用标志以不同于以下字符串的方式打印集合中的第一个字符串,而不是以", "
为前缀)。
请注意,由于您观察容器中的元素,因此您可能希望在range-for循环中使用const auto&
。
#include <iostream>
#include <map>
#include <set>
#include <string>
using namespace std;
int main() {
// Fill the data structure with some test data
map<string, set<string>> data;
data["Key1"].emplace("hello");
data["Key1"].emplace("world");
data["Key1"].emplace("test");
data["Key2"].emplace("Ciao");
data["Key2"].emplace("Mondo");
// For each item in the outer map
for (const auto& x : data) {
// Print item's key
cout << x.first << ": ";
// Special output for the first string in the set
bool first = true;
// Note: x.first is the key, x.second is the associated set.
// For each string in the set:
for (const auto& s : x.second) {
// Prefix every string except the first one with ", "
if (!first) {
cout << ", ";
} else {
first = false;
}
// Print current string in the set
cout << s;
}
cout << endl;
}
return 0;
}
输出:
Key1: hello, test, world Key2: Ciao, Mondo
答案 3 :(得分:1)
我通常使用迭代器来加入字符串。
for (auto& i : data) {
cout << i.first << ':';
auto p = i.second.begin();
auto q = i.second.end();
if (p != q) {
cout << ' ' << *p;
for (++p; p != q; ++p) {
cout << ", " << *p;
}
}
cout << '\n';
}
答案 4 :(得分:1)
您将找不到“完美”的解决方案。基本上,你想为每个元素做同样的事情(凭借基于范围的for循环),但仍然以不同的方式处理一个案例。那不是一起来的。你可以做的一件事是使用一个额外的标志来不同地处理第一个元素:
bool first_element = true;
for ( auto i : data )
{
if ( !first_element)
{
// print ","
}
// print i;
first_element = false;
}
一般情况下,如果这只是项目中某个地方的一小段代码,请不要过于担心。
答案 5 :(得分:0)
template<typename R>
struct not_last_t {
R r;
not_last_t(R&& in):r(std::forward<R>(in)){}
not_last_t(not_last_t&&)=default;
void operator=(not_last_t&&)=delete;
// C++14 because lazy. Can be written in C++11:
auto begin() { using std::begin; return begin(r); }
auto end() {
using std::end; auto ret=end(r);
if(ret==begin()) return ret;
return std::next(ret,-1);
}
};
template<typename R>
not_last_t<R> not_last(R&&r){return {sts::forward<R>(r);}}
使用:
for(auto x:not_last(s))
std::cout << x << ", ";
if (!s.empty())
std::cout << s.back();
在使用时高效清晰。在图书馆里笨重。
使用一些C ++ 14功能,因为我很懒,而且可能充满了拼写错误。如果有兴趣,我可以清理代码。