-1

I have the following code in C++

std::map<const std::string, JsonNode *>::iterator it;
std::map<const std::string, JsonNode *>::reverse_iterator last = vals.rbegin();
last++;

for (it = vals.begin(); it != vals.end(); it++){
    if (it == last.base())
    {
        str += it->first + ":" +it->second->toString();
    }else{
        str += it->first + ":" +it->second->toString() + ",";
    }
}

It work well, but a need to to the same thing in reverse order. I began like that

std::map<const std::string, JsonNode *>::iterator first = vals.begin();
std::map<const std::string, JsonNode *>::reverse_iterator it;
first++;

for (it = vals.rbegin(); it != vals.rend(); it++){

    if (<condition>)
    {
        str += it->first + ":" +it->second->toString();
    }else{
        str += it->first + ":" +it->second->toString() + ",";
    }
}

but I don't know what to write as if condition

Polla Toube
  • 178
  • 3
  • 10
  • `base()` is only for `std::map<...>::reverse_iterator`. I am looking for an equivalent on `std::map<...>::iterator` – Polla Toube Jul 12 '18 at 10:41
  • Possible duplicate of [Printing lists with commas C++](https://stackoverflow.com/questions/3496982/printing-lists-with-commas-c) – Caleth Jul 12 '18 at 11:08

4 Answers4

0

I finally use this solution

std::map<const std::string, JsonNode *>::reverse_iterator it;
for (it = vals.rbegin(); it != vals.rend(); it++){
    str += it->first + ":" +it->second->toString() + ",";
}
str.erase(str.size() - 1);

Thanks.

Polla Toube
  • 178
  • 3
  • 10
0

If you compare the indexing iterator to --vals.rend() it should work. See the example below.

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

using MyMap = std::map<const std::string, std::string>;

std::string f(MyMap const &vals)
{
  std::string str;
  MyMap::const_reverse_iterator it;
  MyMap::const_reverse_iterator first = --vals.rend();

  for (it = vals.rbegin(); it != vals.rend(); it++) {
    if (it == first) {
      str += it->first + ":" + it->second;
    } else {
      str += it->first + ":" + it->second + ",";
    }
  }

  return str;
}

int main()
{
  MyMap a{{"a", "b"}, {"c","d"}};

  std::cout << f(a) << "\n";
}
Johan
  • 3,667
  • 6
  • 20
  • 25
0

You don't need reverse_iterator in the first example. Also you should use stringstream because adding strings is very inefficient. Here's how I would do it:

ostringstream stream(str);
auto it = vals.begin();
auto last = --vals.end();

for (; it != vals.end(); it++) {
    if (it == last) {
        stream << it->first << ":" << it->second->toString();
    } else {
        stream << it->first << ":" << it->second->toString() << ",";
    }
}

str = stream.str();

I'm assuming you're using at least C++11, if you're not then just replace auto with actual types.

About reverse order, you can just use reverse_iterator instead of iterator in above example and it'll work as well.

Jakub Nowak
  • 316
  • 2
  • 10
0

If you have an ostream_joiner iterator (either from this answer or std::experimental), it becomes very simple

std::stringstream ss;
auto elem_to_string = [](MyMap::const_reference pair){ return pair.first + ":" + pair.second; };
std::transform(vals.rbegin(), vals.rend(), make_ostream_joiner(ss, ","), elem_to_string);
return ss.str();

And similar for the non-reverse version.

Caleth
  • 52,200
  • 2
  • 44
  • 75