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
});
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);
});
Though this isn't shorter than a for loop:
for (auto const& e : digits) {
counting.emplace(e.first, 0);
}