If I have a std::map and std::unordered_map how could I use pointers on the double so that when the unordered_map updates the double value for a particular key, this is already reflected in the std::map for the same "key"?
So:
unordered_map["1"] = 6 causes map["1"] to be 6 also....
There's no reason why you can't use pointers.
Example:
#include <iostream>
#include <map>
#include <unordered_map>
#include <memory>
int main()
{
std::unordered_map<std::string, std::shared_ptr<double>> umap;
std::map<std::string, std::shared_ptr<double>> omap;
std::shared_ptr<double> value(new double(1234.5));
umap.emplace("key", value);
omap.emplace("key", value);
std::cout << "umap " << *umap["key"] << "\n";
std::cout << "omap " << *omap["key"] << "\n";
*umap["key"] = 9999.1;
std::cout << "omap " << *omap["key"] << "\n";
}
Output:
umap 1234.5
omap 1234.5
omap 9999.1
Maybe like this:
std::unordered_map<std::string, double> um;
std::unordered_map<std::string, double*> om;
om["1"] = &um["1"];
From now on, *om["1"] is always the value of the corresponding element in um. Just make sure you never delete elements from the unordered map.
(Source: iterator and reference invalidation rules)
Related
#include <iostream>
#include <map>
using namespace std;
int main()
{
std::map<int, bool> set;
cout << (int)set.insert({ 5,false }).second << endl;
return 0;
}
I don't know why the result is 1 instead of 0, while second is false.
std::map::insert's return value is an std::pair<iterator, bool> where the bool denotes whether insertion took place. cout << (int)set.insert({ 5,false }).second << endl; will only print whether insertion successfully took place.
To do what you want, you'll want to use the first value in the returned std::pair which is an iterator and then use that to check the value of the new key/value pair that you inserted:
#include <iostream>
#include <map>
int main()
{
std::map<int, bool> set;
std::cout << set.insert({5, false}).first->second << '\n';
return 0;
}
I have a std::map which store a key with a vector of std::any.
The purpose is to store all values and print them (with the different types) for each key.
No other operations are performed on the container, only "insertion" and "clean".
I want to clarify that the container is filled (and emptied) very frequently, so i need an efficient container.
It all works with my code. The problem, however, is that when i print the values they are sorted according to the key, but i have to print (or store) them by insertion order.
My code:
#include <iostream>
#include <map>
#include <vector>
#include <any>
std::map<int, std::vector<std::any>> testMap;
void insertMap(int value, std::vector<std::any> tempVector);
void printMap();
int main()
{
std::vector<std::any> tempVector;
tempVector.clear();
tempVector.push_back(1000);
tempVector.push_back((std::string)"hello");
tempVector.push_back(0.10f);
insertMap(10, tempVector);
tempVector.clear();
tempVector.push_back(1500);
tempVector.push_back((std::string)"hello2");
tempVector.push_back(0.20f);
insertMap(5, tempVector);
tempVector.clear();
tempVector.push_back(2000);
tempVector.push_back((std::string)"hello3");
tempVector.push_back(0.5f);
insertMap(7, tempVector);
// etc..
printMap();
}
void insertMap(int value, std::vector<std::any> tempVector)
{
testMap[value].insert(testMap[value].end(), tempVector.begin(), tempVector.end());
}
void printMap()
{
for (const auto& [key, value] : testMap)
{
std::cout << "key=" << key << "\n";
for(auto vec_iter : value)
{
if (vec_iter.type() == typeid(int))
std::cout << "\t" << "int=" << std::any_cast<int>(vec_iter) << "\n";
else if (vec_iter.type() == typeid(float))
std::cout << "\t" << "float=" << std::any_cast<float>(vec_iter) << "\n";
else if (vec_iter.type() == typeid(std::string))
std::cout << "\t" << "string=" << std::any_cast<std::string>(vec_iter) << "\n";
}
}
}
Output:
key=5
key=7
key=10
Expected output:
key=10
key=5
key=7
I tried to using unordered_map but it doesn't print them by insertion order.
So which container could i use? What could be the best performance in my case?
I thought that i could use a std::vector< std::map<int, std::vector<std::any>> > (vector that store std::map). But is it fast? Is there a better solution?
There is no standard library container that both provides fast access by key (which is presumably why you're using std::map to begin with) and "preserves insertion order". If you really need access by key, then iteration order is something you give up control over.
If you need to recover the order of insertion, then you are going to have to preserve it. The simplest way to do that is to just store a vector of map iterators alongside your map. When you insert an item into the map, push the new iterator for it to the back of the vector too.
If you are in a position to use Boost, Boost.MultiIndex can be resorted to:
Live Coliru Demo
#include <iostream>
#include <vector>
#include <any>
#include <utility>
#include <boost/multi_index_container.hpp>
#include <boost/multi_index/ordered_index.hpp>
#include <boost/multi_index/sequenced_index.hpp>
#include <boost/multi_index/key.hpp>
struct test_map_value_type
{
test_map_value_type(int first, const std::vector<std::any>& second):
first{first},second{second}{}
int first;
mutable std::vector<std::any> second;
};
boost::multi_index_container<
test_map_value_type,
boost::multi_index::indexed_by<
boost::multi_index::ordered_unique<
boost::multi_index::key<&test_map_value_type::first>
>,
boost::multi_index::sequenced<>
>
> testMap;
void insertMap(int value, std::vector<std::any> tempVector);
void printMap();
int main()
{
std::vector<std::any> tempVector;
tempVector.clear();
tempVector.push_back(1000);
tempVector.push_back((std::string)"hello");
tempVector.push_back(0.10f);
insertMap(10, tempVector);
tempVector.clear();
tempVector.push_back(1500);
tempVector.push_back((std::string)"hello2");
tempVector.push_back(0.20f);
insertMap(5, tempVector);
tempVector.clear();
tempVector.push_back(2000);
tempVector.push_back((std::string)"hello3");
tempVector.push_back(0.5f);
insertMap(7, tempVector);
// etc..
printMap();
}
void insertMap(int value, std::vector<std::any> tempVector)
{
auto it=testMap.emplace(value,std::vector<std::any>{}).first;
it->second.insert(it->second.end(), tempVector.begin(), tempVector.end());
}
void printMap()
{
for (const auto& [key, value] : testMap.get<1>())
{
std::cout << "key=" << key << "\n";
for(auto vec_iter : value)
{
if (vec_iter.type() == typeid(int))
std::cout << "\t" << "int=" << std::any_cast<int>(vec_iter) << "\n";
else if (vec_iter.type() == typeid(float))
std::cout << "\t" << "float=" << std::any_cast<float>(vec_iter) << "\n";
else if (vec_iter.type() == typeid(std::string))
std::cout << "\t" << "string=" << std::any_cast<std::string>(vec_iter) << "\n";
}
}
}
Output
key=10
int=1000
string=hello
float=0.1
key=5
int=1500
string=hello2
float=0.2
key=7
int=2000
string=hello3
float=0.5
This is a follow up question from Cout from a map with std::tuple
I have made a small map that I call BMW. It contains the keys Usage and Diesel, as shown below.
#include <iostream>
#include <bits/stdc++.h>
#include <map>
#include <vector>
using namespace std;
int main()
{
// initialize container
map<string, tuple<string, string>> BMW;
// insert elements
BMW.insert({"Usage", {"1", "2"}});
BMW.insert({"Disel", {"2", "3"}});
string sFirst_value;
string sSecond_value;
//prints out the map
for (const auto& x : BMW) {
sFirst_value.assign(get<0>(BMW.find(x.first)->second));
sSecond_value.assign(get<1>(BMW.find(x.first)->second));
cout << x.first << "\n" << "Min: " << sFirst_value << "\n" << "Max: " << sSecond_value << "\n" << "\n";
}
return 0;
}
Is there anyway I can call the name of the map, BMW, from a string instead of writing BMW.insert({"Usage", {"1", "2"}});? Like this:
stirng Mycar;
Mycar.insert({"Usage", {"1", "2"}});
To expand on Quentin's comment with a small example:
std::map<std::string, std::map<std::string, std::tuple<std::string, std::string>>> mapMap;
std::string myCar = "BMW";
std::map<std::string, std::tuple<std::string, std::string>> &myCarMap = mapMap[myCar];
myCarMap.insert({"Usage", {"1", "2"}});
//Or simply
auto &bmwMap = mapMap["BMW"];
bmwMap.insert({"Usage", {"1", "2"}});
}
Probably you can find better names than mapMap though ;)
I'm don't get this to work. I want to initialize the following structure for later use.
map<pair<string,string>, map<string,vector<fs::path>>> filelist;
Thats means I provide the string pair for the first map. (e.g., "id1","id2") with an empty second map that I can fill in later. So I want to do something like this:
filelist.insert(
pair<pair<string,string>, pair<string,vector<fs::path>>>
(make_pair("id1","id2), **empty map??**));
Obviously when when I stick to the vector instead of the nested map I can do this:
filelist.insert(pair<pair<string, string>, vector<vector<fs::path>>>
(make_pair("id1","id2"),{}) );
But how can I initialize an empty map? Or is there an alternative data structure? Thanks
I want to initialize the following structure for later use.
map<pair<string,string>, map<string,vector<fs::path>>> filelist;
You can use operator[] to assign it.
Some thing like follows.
filelist[ std::make_pair("string1", "string2") ] = value();
where, using value = std::map< std::string, std::vector<int>>;
See live action: https://www.ideone.com/lxQir7
is there an alternative data structure?
A suggestion to reduce the complexity of your chosen data-structure is possible, only when you explain your problem and data manipulation requirements more in detail.
#include <iostream>
#include <map>
#include <string>
#include <vector>
using key = std::pair< std::string, std::string>;
using value = std::map< std::string, std::vector<int>>;
int main ()
{
std::map< key , value > filelist;
value vMap;
vMap["string"] = {1,2,3,4};
filelist[ std::make_pair("string1", "string2") ] = vMap;
// to print or access
for(auto& key_itr: filelist)
{
std::cout<< "KEY: " << key_itr.first.first << " " << key_itr.first.second << "\t VALUE: ";
for(auto& val_itr: key_itr.second)
{
std::cout << val_itr.first << " ";
for(const auto& vec: val_itr.second) std::cout << vec << " ";
}
std::cout << std::endl;
}
return 0;
}
You can initialize an empty map, simply by its default constructor.
It is always a better idea to name your newly introduced data types.
After all, it's a relatively complex data structure. Why don't you simplify your problem?
#include <map>
#include <vector>
#include <filesystem>
using namespace std;
using namespace std::filesystem;
using string_to_vector_of_path_map = map<string, vector<path>>;
using pair_of_strings = pair<string, string>;
using my_map = map<pair_of_strings, string_to_vector_of_path_map>;
my_map filelist;
int main()
{
filelist.insert(make_pair(make_pair("id1", "id2"), string_to_vector_of_path_map()));
return 0;
}
STL map "[]" operator can insert new entries or modify existing entries.
map<string, string> myMap;
myMap["key1"] = "value1";
myMap["key1"] = "value2";
I am rewriting some code with boost::bimap which was implemented by STL map. Is there an easy way to keep the STL "[]" behavior? I found I have to write below 7 lines code to replace the original STL map code (1 line!).
bimap<string, string>::left_iterator itr = myBimap.left.find("key1");
if (itr != myBimap.left.end()) {
myBimap.left.replace_data(itr, "value2");
}
else {
myBimap.insert(bimap<string, string>::value_type("key1", "value2"));
}
I was wondering if there's an utility function like boost::bimap::insert_or_modify().
The Boost.Bimap documentation shows how mimic a std::map including its operator[] by using set_of and list_of for the bimap template arguments:
#include <iostream>
#include <string>
#include <boost/bimap.hpp>
#include <boost/bimap/set_of.hpp>
#include <boost/bimap/list_of.hpp>
int main()
{
using namespace std;
map<string, string> myMap;
myMap["key1"] = "value1";
myMap["key1"] = "value2";
for (auto&& elem : myMap)
std::cout << "{" << elem.first << ", " << elem.second << "}, ";
std::cout << "\n";
using namespace boost::bimaps;
bimap<set_of<string>, list_of<string>> myMap2;
myMap2.left["key1"] = "value1";
myMap2.left["key1"] = "value2";
for (auto&& elem : myMap2.left)
std::cout << "{" << elem.first << ", " << elem.second << "}, ";
std::cout << "\n";
auto res1 = myMap2.left.find("key1");
std::cout << "{" << res1->first << ", " << res1->second << "} \n";
}
Live Example.
UPDATE: the above code also allows left-searches. However, a right-search is not possible in combination with the required operator[] syntax. The reason is that operator[] modifications can only be done with a mutable right-view (such list_of or vector_of). OTOH, right-searches can only be done from immutable set_of and unordered_set_of and their multi- cousins.