I have a task to fill empty std::map<char, std::set<std::string>> myMap, by an array
const char* s[] = { "car", "sun", "surprise", "asteriks", "alpha", "apple" };
and print it using range based for and bindings. Result, should be like S: sun, surprise
The last one(printing) I have already implement in this way
for (const auto& [k, v] : myMap)
{
cout << "k = " << k << endl;
std::set<std::string>::iterator it;
for (it = v.begin(); it != v.end(); ++it)
{
cout << "var = " << *it << endl;
}
}
But how can I initilase this map, by const char* s[] in right way?
P.S. I know, how to initialize it like std::map<char, std::set<std::string>> myMap = { {'a', {"abba", "abart", "audi"} } }; and I read this and this posts on StackOverflow, but I am still have no idea, how to do this by this array.
How about this?
const char* s[] = { "car", "sun", "surprise", "asteriks", "alpha", "apple" };
std::map<char, std::set<std::string>> myMap;
for (auto str : s)
myMap[str[0]].insert(str);
// Result: {
// 'a' -> {"alpha", "apple", "asteriks"},
// 'c' -> {"car"},
// 's' -> {"sun", "surprise"}
// }
Related
I have a std::map<std::string, std::vector<std::string>> and I need to perform a threaded task on this map by dividing the map into sub-maps and passing each sub-map to a thread.
With a std::vector<T> I would be able to get a sub-vector pretty easy, by doing this:
#include <vector>
#include <string>
int main(void)
{
size_t off = 0;
size_t num_elms = 100; // Made up value
std::vector<uint8_t> full; // Assume filled with stuff
std::vector<uin8t_t> sub(std::begin(full) + off, std::begin(full) + off + num_elms);
off = off + num_elms;
}
However, doing the same with std::map<T1, T2> gives a compilation error.
#include <vector>
#include <map>
#include <string>
int main(void)
{
size_t off = 0;
size_t num_elms = 100;
std::map<std::string, std::vector<std::string>> full;
std::map<std::string, std::vector<std::string>> sub(std::begin(full) + off,
std::begin(full) + off + num_elms);
off = off + num_elms;
}
It is the same with other std::map "types". Which, from what I have gathered, is down to the iterator.
What is possible is to extract the keys and do something similar to this solution:
#include <map>
#include <vector>
#include <string>
#include <iostream>
void print_map(const std::map<std::string, std::vector<std::string>>& _map)
{
for (const auto& [key, value] : _map)
{
std::cout << "key: " << key << "\nvalues\n";
for (const auto& elm : value)
{
std::cout << "\t" << elm << "\n";
}
}
}
void print_keys(const std::vector<std::string>& keys)
{
std::cout << "keys: \n";
for(const auto& key : keys)
{
std::cout << key << "\n";
}
}
int main(void)
{
std::map<std::string, std::vector<std::string>> full;
full["aa"] = {"aa", "aaaa", "aabb"};
full["bb"] = {"bb", "bbbbb", "bbaa"};
full["cc"] = {"cc", "cccc", "ccbb"};
full["dd"] = {"dd", "dd", "ddcc"};
print_map(full);
std::vector<std::string> keys;
for (const auto& [key, value] : full)
{
(void) value;
keys.emplace_back(key);
}
print_keys(keys);
size_t off = 0;
size_t num_elms = 2;
std::map<std::string, std::vector<std::string>> sub1 (full.find(keys.at(off)), full.find(keys.at(off + num_elms)));
off = off + num_elms;
std::map<std::string, std::vector<std::string>> sub2 (full.find(keys.at(off)), full.find(keys.at(off + num_elms -1)));
std::cout << "sub1:\n";
print_map(sub1);
std::cout << "sub2:\n";
print_map(sub2);
}
However, this has the potential to be extremely inefficient, as the map can be really big (10k+ elements).
So, is there a better way to replicate the std::vector approach with std::map?
A slightly different approach would be to use one of the execution policies added in C++17, like std::execution::parallel_policy. In the example below, the instance std::execution::par is used:
#include <execution>
// ...
std::for_each(std::execution::par, full.begin(), full.end(), [](auto& p) {
// Here you are likely using a thread from a built-in thread pool
auto& vec = p.second;
// do work with "vec"
});
With a slight adaption, you can reasonably easily pass ranges to print_map, and divide up your map by calling std::next on an iterator.
// Minimal range-for support
template <typename Iter>
struct Range {
Range (Iter b, Iter e) : b(b), e(e) {}
Iter b;
Iter e;
Iter begin() const { return b; }
Iter end() const { return e; }
};
// some shorter aliases
using Map = std::map<std::string, std::vector<std::string>>;
using MapView = Range<Map::const_iterator>;
// not necessarily the whole map
void print_map(MapView map) {
for (const auto& [key, value] : map)
{
std::cout << "key: " << key << "\nvalues\n";
for (const auto& elm : value)
{
std::cout << "\t" << elm << "\n";
}
}
}
int main(void)
{
Map full;
full["aa"] = {"aa", "aaaa", "aabb"};
full["bb"] = {"bb", "bbbbb", "bbaa"};
full["cc"] = {"cc", "cccc", "ccbb"};
full["dd"] = {"dd", "dd", "ddcc"};
// can still print the whole map
print_map({ map.begin(), map.end() });
size_t num_elms = 2;
size_t num_full_views = full.size() / num_elms;
std::vector<MapView> views;
auto it = full.begin();
for (size_t i = 0; i < num_full_views; ++i) {
auto next = std::next(it, num_elms);
views.emplace_back(it, next);
it = next;
}
if (it != full.end()) {
views.emplace_back(it, full.end());
}
for (auto view : views) {
print_map(view);
}
}
In C++20 (or with another ranges library), this can be simplified with std::ranges::drop_view / std::ranges::take_view.
using MapView = decltype(std::declval<Map>() | std::ranges::views::drop(0) | std::ranges::views::take(0));
for (size_t i = 0; i < map.size(); i += num_elms) {
views.push_back(map | std::ranges::views::drop(i) | std::ranges::views::take(num_elms));
}
I had to count the words of a vector and put it in a map that counts the words. Then the function showFrequencies has to show/print the map.
map<string, int>CountWords(vector<string> words) {
map<string, int> count;
for(auto i = words.begin(); i != words.end(); i++) {
count[*i]++;
}
return count;
}
void showFrequencies(CountWords(vector<string> name)) {
for (map<string, int>::const_iterator it = count.begin(); it !=
count.end(); ++it) {
cout << it->first << "\t" << it->second;}
}
int main(){
vector<string> words = {"hello", "you", "hello", "me", "chipolata", "you"};
showFrequencies(CountWords(words));
return 0;
}
void showFrequencies(CountWords(vector<string> name)) {
should be
void showFrequencies(const map<string, int>& name) {
How can I loop through a std::map in C++? My map is defined as:
std::map< std::string, std::map<std::string, std::string> >
For example, the above container holds data like this:
m["name1"]["value1"] = "data1";
m["name1"]["value2"] = "data2";
m["name2"]["value1"] = "data1";
m["name2"]["value2"] = "data2";
m["name3"]["value1"] = "data1";
m["name3"]["value2"] = "data2";
How can I loop through this map and access the various values?
Old question but the remaining answers are outdated as of C++11 - you can use a ranged based for loop and simply do:
std::map<std::string, std::map<std::string, std::string>> mymap;
for(auto const &ent1 : mymap) {
// ent1.first is the first key
for(auto const &ent2 : ent1.second) {
// ent2.first is the second key
// ent2.second is the data
}
}
this should be much cleaner than the earlier versions, and avoids unnecessary copies.
Some favour replacing the comments with explicit definitions of reference variables (which get optimised away if unused):
for(auto const &ent1 : mymap) {
auto const &outer_key = ent1.first;
auto const &inner_map = ent1.second;
for(auto const &ent2 : inner_map) {
auto const &inner_key = ent2.first;
auto const &inner_value = ent2.second;
}
}
You can use an iterator.
typedef std::map<std::string, std::map<std::string, std::string>>::iterator it_type;
for(it_type iterator = m.begin(); iterator != m.end(); iterator++) {
// iterator->first = key
// iterator->second = value
// Repeat if you also want to iterate through the second map.
}
for(std::map<std::string, std::map<std::string, std::string> >::iterator outer_iter=map.begin(); outer_iter!=map.end(); ++outer_iter) {
for(std::map<std::string, std::string>::iterator inner_iter=outer_iter->second.begin(); inner_iter!=outer_iter->second.end(); ++inner_iter) {
std::cout << inner_iter->second << std::endl;
}
}
or nicer in C++0x:
for(auto outer_iter=map.begin(); outer_iter!=map.end(); ++outer_iter) {
for(auto inner_iter=outer_iter->second.begin(); inner_iter!=outer_iter->second.end(); ++inner_iter) {
std::cout << inner_iter->second << std::endl;
}
}
With C++17 (or later), you can use the "structured bindings" feature, which lets you define multiple variables, with different names, using a single tuple/pair. Example:
for (const auto& [name, description] : planet_descriptions) {
std::cout << "Planet " << name << ":\n" << description << "\n\n";
}
The original proposal (by luminaries Bjarne Stroustrup, Herb Sutter and Gabriel Dos Reis) is fun to read (and the suggested syntax is more intuitive IMHO); there's also the proposed wording for the standard which is boring to read but is closer to what will actually go in.
Do something like this:
typedef std::map<std::string, std::string> InnerMap;
typedef std::map<std::string, InnerMap> OuterMap;
Outermap mm;
...//set the initial values
for (OuterMap::iterator i = mm.begin(); i != mm.end(); ++i) {
InnerMap &im = i->second;
for (InnerMap::iterator ii = im.begin(); ii != im.end(); ++ii) {
std::cout << "map["
<< i->first
<< "]["
<< ii->first
<< "] ="
<< ii->second
<< '\n';
}
}
C++11:
std::map< std::string, std::map<std::string, std::string> > m;
m["name1"]["value1"] = "data1";
m["name1"]["value2"] = "data2";
m["name2"]["value1"] = "data1";
m["name2"]["value2"] = "data2";
m["name3"]["value1"] = "data1";
m["name3"]["value2"] = "data2";
for (auto i : m)
for (auto j : i.second)
cout << i.first.c_str() << ":" << j.first.c_str() << ":" << j.second.c_str() << endl;
output:
name1:value1:data1
name1:value2:data2
name2:value1:data1
name2:value2:data2
name3:value1:data1
name3:value2:data2
As einpoklum mentioned in their answer, since C++17 you can also use structured binding declarations. I want to extend on that by providing a full solution for iterating over a map of maps in a comfortable way:
int main() {
std::map<std::string, std::map<std::string, std::string>> m {
{"name1", {{"value1", "data1"}, {"value2", "data2"}}},
{"name2", {{"value1", "data1"}, {"value2", "data2"}}},
{"name3", {{"value1", "data1"}, {"value2", "data2"}}}
};
for (const auto& [k1, v1] : m)
for (const auto& [k2, v2] : v1)
std::cout << "m[" << k1 << "][" << k2 << "]=" << v2 << std::endl;
return 0;
}
Output:
m[name1][value1]=data1
m[name1][value2]=data2
m[name2][value1]=data1
m[name2][value2]=data2
m[name3][value1]=data1
m[name3][value2]=data2
Note 1: For filling the map, I used an initializer list (which is a C++11 feature). This can sometimes be handy to keep fixed initializations compact.
Note 2: If you want to modify the map m within the loops, you have to remove the const keywords.
Code on Coliru
use std::map< std::string, std::map<std::string, std::string> >::const_iterator when map is const.
First solution is Use range_based for loop, like:
Note: When range_expression’s type is std::map then a range_declaration’s type is std::pair.
for ( range_declaration : range_expression )
//loop_statement
Code 1:
typedef std::map<std::string, std::map<std::string, std::string>> StringToStringMap;
StringToStringMap my_map;
for(const auto &pair1 : my_map)
{
// Type of pair1 is std::pair<std::string, std::map<std::string, std::string>>
// pair1.first point to std::string (first key)
// pair1.second point to std::map<std::string, std::string> (inner map)
for(const auto &pair2 : pair1.second)
{
// pair2.first is the second(inner) key
// pair2.second is the value
}
}
The Second Solution:
Code 2
typedef std::map<std::string, std::string> StringMap;
typedef std::map<std::string, StringMap> StringToStringMap;
StringToStringMap my_map;
for(StringToStringMap::iterator it1 = my_map.begin(); it1 != my_map.end(); it1++)
{
// it1->first point to first key
// it2->second point to inner map
for(StringMap::iterator it2 = it1->second.begin(); it2 != it1->second.end(); it2++)
{
// it2->second point to value
// it2->first point to second(inner) key
}
}
How can I loop through a std::map in C++? My map is defined as:
std::map< std::string, std::map<std::string, std::string> >
For example, the above container holds data like this:
m["name1"]["value1"] = "data1";
m["name1"]["value2"] = "data2";
m["name2"]["value1"] = "data1";
m["name2"]["value2"] = "data2";
m["name3"]["value1"] = "data1";
m["name3"]["value2"] = "data2";
How can I loop through this map and access the various values?
Old question but the remaining answers are outdated as of C++11 - you can use a ranged based for loop and simply do:
std::map<std::string, std::map<std::string, std::string>> mymap;
for(auto const &ent1 : mymap) {
// ent1.first is the first key
for(auto const &ent2 : ent1.second) {
// ent2.first is the second key
// ent2.second is the data
}
}
this should be much cleaner than the earlier versions, and avoids unnecessary copies.
Some favour replacing the comments with explicit definitions of reference variables (which get optimised away if unused):
for(auto const &ent1 : mymap) {
auto const &outer_key = ent1.first;
auto const &inner_map = ent1.second;
for(auto const &ent2 : inner_map) {
auto const &inner_key = ent2.first;
auto const &inner_value = ent2.second;
}
}
You can use an iterator.
typedef std::map<std::string, std::map<std::string, std::string>>::iterator it_type;
for(it_type iterator = m.begin(); iterator != m.end(); iterator++) {
// iterator->first = key
// iterator->second = value
// Repeat if you also want to iterate through the second map.
}
for(std::map<std::string, std::map<std::string, std::string> >::iterator outer_iter=map.begin(); outer_iter!=map.end(); ++outer_iter) {
for(std::map<std::string, std::string>::iterator inner_iter=outer_iter->second.begin(); inner_iter!=outer_iter->second.end(); ++inner_iter) {
std::cout << inner_iter->second << std::endl;
}
}
or nicer in C++0x:
for(auto outer_iter=map.begin(); outer_iter!=map.end(); ++outer_iter) {
for(auto inner_iter=outer_iter->second.begin(); inner_iter!=outer_iter->second.end(); ++inner_iter) {
std::cout << inner_iter->second << std::endl;
}
}
With C++17 (or later), you can use the "structured bindings" feature, which lets you define multiple variables, with different names, using a single tuple/pair. Example:
for (const auto& [name, description] : planet_descriptions) {
std::cout << "Planet " << name << ":\n" << description << "\n\n";
}
The original proposal (by luminaries Bjarne Stroustrup, Herb Sutter and Gabriel Dos Reis) is fun to read (and the suggested syntax is more intuitive IMHO); there's also the proposed wording for the standard which is boring to read but is closer to what will actually go in.
Do something like this:
typedef std::map<std::string, std::string> InnerMap;
typedef std::map<std::string, InnerMap> OuterMap;
Outermap mm;
...//set the initial values
for (OuterMap::iterator i = mm.begin(); i != mm.end(); ++i) {
InnerMap &im = i->second;
for (InnerMap::iterator ii = im.begin(); ii != im.end(); ++ii) {
std::cout << "map["
<< i->first
<< "]["
<< ii->first
<< "] ="
<< ii->second
<< '\n';
}
}
C++11:
std::map< std::string, std::map<std::string, std::string> > m;
m["name1"]["value1"] = "data1";
m["name1"]["value2"] = "data2";
m["name2"]["value1"] = "data1";
m["name2"]["value2"] = "data2";
m["name3"]["value1"] = "data1";
m["name3"]["value2"] = "data2";
for (auto i : m)
for (auto j : i.second)
cout << i.first.c_str() << ":" << j.first.c_str() << ":" << j.second.c_str() << endl;
output:
name1:value1:data1
name1:value2:data2
name2:value1:data1
name2:value2:data2
name3:value1:data1
name3:value2:data2
As einpoklum mentioned in their answer, since C++17 you can also use structured binding declarations. I want to extend on that by providing a full solution for iterating over a map of maps in a comfortable way:
int main() {
std::map<std::string, std::map<std::string, std::string>> m {
{"name1", {{"value1", "data1"}, {"value2", "data2"}}},
{"name2", {{"value1", "data1"}, {"value2", "data2"}}},
{"name3", {{"value1", "data1"}, {"value2", "data2"}}}
};
for (const auto& [k1, v1] : m)
for (const auto& [k2, v2] : v1)
std::cout << "m[" << k1 << "][" << k2 << "]=" << v2 << std::endl;
return 0;
}
Output:
m[name1][value1]=data1
m[name1][value2]=data2
m[name2][value1]=data1
m[name2][value2]=data2
m[name3][value1]=data1
m[name3][value2]=data2
Note 1: For filling the map, I used an initializer list (which is a C++11 feature). This can sometimes be handy to keep fixed initializations compact.
Note 2: If you want to modify the map m within the loops, you have to remove the const keywords.
Code on Coliru
use std::map< std::string, std::map<std::string, std::string> >::const_iterator when map is const.
First solution is Use range_based for loop, like:
Note: When range_expression’s type is std::map then a range_declaration’s type is std::pair.
for ( range_declaration : range_expression )
//loop_statement
Code 1:
typedef std::map<std::string, std::map<std::string, std::string>> StringToStringMap;
StringToStringMap my_map;
for(const auto &pair1 : my_map)
{
// Type of pair1 is std::pair<std::string, std::map<std::string, std::string>>
// pair1.first point to std::string (first key)
// pair1.second point to std::map<std::string, std::string> (inner map)
for(const auto &pair2 : pair1.second)
{
// pair2.first is the second(inner) key
// pair2.second is the value
}
}
The Second Solution:
Code 2
typedef std::map<std::string, std::string> StringMap;
typedef std::map<std::string, StringMap> StringToStringMap;
StringToStringMap my_map;
for(StringToStringMap::iterator it1 = my_map.begin(); it1 != my_map.end(); it1++)
{
// it1->first point to first key
// it2->second point to inner map
for(StringMap::iterator it2 = it1->second.begin(); it2 != it1->second.end(); it2++)
{
// it2->second point to value
// it2->first point to second(inner) key
}
}
I want to do something like this. Is there a stl algorithm that does this easily?
for each(auto aValue in aVector)
{
aMap[aValue] = 1;
}
If you have a vector of pairs, where the first item in the pair will be the key for the map, and the second item will be the value associated with that key, you can just copy the data to the map with an insert iterator:
std::vector<std::pair<std::string, int> > values {
{"Jerry", 1},
{ "Jim", 2},
{ "Bill", 3} };
std::map<std::string, int> mapped_values;
std::copy(values.begin(), values.end(),
std::inserter(mapped_values, mapped_values.begin()));
or, you could initialize the map from the vector:
std::map<std::string, int> m2((values.begin()), values.end());
Maybe like this:
std::vector<T> v; // populate this
std::map<T, int> m;
for (auto const & x : v) { m[x] = 1; }
You might std::transform the std::vector into a std::map
std::vector<std::string> v{"I", "want", "to", "do", "something", "like", "this"};
std::map<std::string, int> m;
std::transform(v.begin(), v.end(), std::inserter(m, m.end()),
[](const std::string &s) { return std::make_pair(s, 1); });
This creates std::pairs from the vector's elements, which in turn are inserted into the map.
Or, as suggested by #BenFulton, zipping two vectors into a map
std::vector<std::string> k{"I", "want", "to", "do", "something", "like", "this"};
std::vector<int> v{1, 2, 3, 4, 5, 6, 7};
std::map<std::string, int> m;
auto zip = [](const std::string &s, int i) { return std::make_pair(s, i); };
std::transform(k.begin(), k.end(), v.begin(), std::inserter(m, m.end()), zip);
Assuming items in vector are related in order, maybe this example can help :
#include <map>
#include <vector>
#include <string>
#include <iostream>
std::map<std::string, std::string> convert_to_map(const std::vector<std::string>& vec)
{
std::map<std::string, std::string> mp;
std::pair<std::string, std::string> par;
for(unsigned int i=0; i<vec.size(); i++)
{
if(i == 0 || i%2 == 0)
{
par.first = vec.at(i);
par.second = std::string();
if(i == (vec.size()-1))
{
mp.insert(par);
}
}
else
{
par.second = vec.at(i);
mp.insert(par);
}
}
return mp;
}
int main(int argc, char** argv)
{
std::vector<std::string> vec;
vec.push_back("customer_id");
vec.push_back("1");
vec.push_back("shop_id");
vec.push_back("2");
vec.push_back("state_id");
vec.push_back("3");
vec.push_back("city_id");
// convert vector to map
std::map<std::string, std::string> mp = convert_to_map(vec);
// print content:
for (auto it = mp.cbegin(); it != mp.cend(); ++it)
std::cout << " [" << (*it).first << ':' << (*it).second << ']';
std::cout << std::endl;
return 0;
}
A very generic approach to this, since you didn't specify any types, can be done as follows:
template<class Iterator, class KeySelectorFunc,
class Value = std::decay_t<decltype(*std::declval<Iterator>())>,
class Key = std::decay_t<decltype(std::declval<KeySelectorFunc>()(std::declval<Value>()))>>
std::map<Key, Value> toMap(Iterator begin, Iterator end, KeySelectorFunc selector) {
std::map<Key, Value> map;
std::transform(begin, end, std::inserter(map, map.end()), [selector](const Value& value) mutable {
return std::make_pair(selector(value), value);
});
return map;
}
Usage:
struct TestStruct {
int id;
std::string s;
};
std::vector<TestStruct> testStruct = {
TestStruct{1, "Hello"},
TestStruct{2, "Hello"},
TestStruct{3, "Hello"}
};
std::map<int, TestStruct> map = toMap(testStruct.begin(), testStruct.end(),
[](const TestStruct& t) {
return t.id;
}
);
for (const auto& pair : map) {
std::cout << pair.first << ' ' << pair.second.id << ' ' << pair.second.s << '\n';
}
// yields:
// 1 1 Hello
// 2 2 Hello
// 3 3 Hello
The parameter selector function is used to select what to use for the key in the std::map.
Try this:
for (auto it = vector.begin(); it != vector.end(); it++) {
aMap[aLabel] = it;
//Change aLabel here if you need to
//Or you could aMap[it] = 1 depending on what you really want.
}
I assume this is what you are trying to do.
If you want to update the value of aLabel, you could change it in the loop. Also, I look back at the original question, and it was unclear what they wanted so I added another version.
Yet another way:
#include <map>
#include <vector>
#include <boost/iterator/transform_iterator.hpp>
int main() {
using T = double;
std::vector<T> v;
auto f = [](T value) { return std::make_pair(value, 1); };
std::map<T, int> m(boost::make_transform_iterator(v.begin(), f),
boost::make_transform_iterator(v.end(), f));
}
But I don't think it beats range-for loop here in terms of readability and execution speed.
For converting values of a array or a vector directly to map we can do like.
map<int, int> mp;
for (int i = 0; i < m; i++)
mp[a[i]]++;
where a[i] is that array we have with us.