Home > Net >  C STL: Using transform to copy keys of one map into a dissimilar map, filling in default values?
C STL: Using transform to copy keys of one map into a dissimilar map, filling in default values?

Time:11-10

I'm trying to convert something like this:

const map<string, string> digits = {{"zero", "0"},{"one", "1"},{"two", "2"},{"three", "3"},{"four", "4"},{"five", "5"},{"six", "6"},{"seven", "7"},{"eight", "8"},{"nine", "9"}};

Into this:

map<string, uint> out = {{"zero", 0},{"one", 0},{"two", 0},{"three", 0},{"four", 0},{"five", 0},{"six", 0},{"seven", 0},{"eight", 0},{"nine", 0}};

In a short way using STL algorithms.

I've tried many things, but right now I'm at:

map<string, uint> counting;
transform(begin(digits), end(digits), inserter(counting, end(counting)), [](auto & p) {
    return {p.first, 0};
});

and am scratching my head as to how I do this... Is there a way to use the transform algorithm on dissimilar iterators?

CodePudding user response:

The problem is that std::map iterators are bidirectional iterators while std::insert_iterator (created by std::inserter) is an output iterator (as required by std::transform), and the two operator types are not compatible.

Reason being that std::map is ordered and you can't insert values at arbitrary positions.

So you can't use std::transform to copy into a map.

The simplest workaround is a plain range for loop to add elements to the destination map. Or std::for_each as shown in Nelfeal's answer.

CodePudding user response:

You must return a std::map<std::string, uint>::value_type, which is a std::pair<std::string, uint>.

std::transform(std::begin(digits), std::end(digits), std::inserter(counting, std::end(counting)), [](auto & p) {
    return std::pair{p.first, 0}; // deduced template arguments
});

Demo

You can also use std::for_each with a capturing lambda instead:

std::for_each(std::begin(digits), std::end(digits), [&counting](auto & p) {
    counting.emplace(p.first, 0);
});

Demo

Though this isn't shorter than a for loop:

for (auto const& e : digits) {
    counting.emplace(e.first, 0);
}
  • Related