Initialize a map with map-values - c++

I want to initialize a map with map-values in the following way:
std::map<int, std::map<int, int>> map =
{
{ 1, { { 1, 0 }, { 2, 1 } } },
{ 2, { { 1, 1 }, { 2, 0 } } },
};
While this compiles without any error or warning, it raises an exception stating "map/set iterators incompatible". If I remove the second pair, i.e. { 2, { { 1, 1 }, { 2, 0 } } }, no exception is raised and map contains one pair with key 1 and a map containing the pairs (1, 0) and (2, 1) as its value.
I'm sure there is a quite good reason for this (at first glance) somehow strange behavior.
Solution
Nope, there's no good reason. It turned out to be one of the beautiful bugs in Visual Studio 2013.

did you tried with c++11 option?
#include <iostream>
#include <map>
int main()
{
std::map<int, std::map<int, int>> map =
{
{ 1, { { 1, 0 }, { 2, 1 } } },
{ 2, { { 1, 1 }, { 2, 0 } } },
};
auto t = map[1];
std::cout << t[1] << std::endl;
std::cout << t[2] << std::endl;
auto t2 = map[2];
std::cout << t2[1] << std::endl;
std::cout << t2[2] << std::endl;
std::cout << "--------------" << std::endl;
std::cout << map[1][1] << std::endl;
std::cout << map[1][2] << std::endl;
std::cout << map[2][1] << std::endl;
std::cout << map[2][2] << std::endl;
}

Related

How to access the value from the json file using runtime key in c++

I'm new to json and trying to use nlohmann library and I'm quite stuck.
config.json file looks like this
{
"Version": 1.1,
"Size": 1024,
"integer": 600,
"Map": [{"0": "india"}, {"1": "usa"}, {"2": "china"}, {"2": "japan"}],
"name": "xxx",
}
I want to get the value of ["Map"]["1"] where "1" is a runtime entity. I have tried several ways but none of them is working.
std::string strRwFilePath = std::string(CONFIG_PATH) + "config.json";
std::ifstream RwFile(strRwFilePath);
if (RwFile.fail())
{
std::cout << "[ReadFileContents]RwFile doesnt exist" << std::endl;
}
else
{
// parsing input
RwFile >> conf_json;
if(!(conf_json.empty()))
{
//METHOD 1
for (auto it = conf_json["Map"].begin(); it != conf_json["Map"].end(); ++it)
{
std::cout << it.key() << " | " << it.value() << "\n";
std::string keyy = std::to_string(m_iRegionType);
std::string tempKey = it.key(); //ERROR- [json.exception.invalid_iterator.207] cannot use key() for non-object iterators
std::cout << "for loop: tempKey:" << tempKey << " \n";
if(!strcmp(tempKey.c_str(),(std::to_string(m_iRegionType)).c_str()))
{
std::cout << "SUCCESS 222" << std::endl;
break;
}
else
{
std::cout << "FAILURE 222" << std::endl;
}
}
//METHOD 2
for(auto& element : conf_json["Map"].items())
{
std::cout << element.key() << " | " << element.value() << "\n";
m_iRegionType = 2;
std::string keyy = std::to_string(m_iRegionType);
std::string tempKey = element.key(); //ERROR: [json.exception.type_error.302] type must be string, but is object
if(!strcmp(tempKey.c_str(),(std::to_string(m_iRegionType)).c_str()))
{
std::cout << "SUCCESS 333" << std::endl;
break;
}
else
{
std::cout << "FAILURE 333" << std::endl;
}
}
//METHOD 3
std::string strTempKey = std::to_string(m_iRegionType);
if(!conf_json["Map"][strTempKey.c_str()].is_null())
{
std::string strName = conf_json["Map"][strTempKey.c_str()]; //ERROR: [json.exception.type_error.305] cannot use operator[] with a string argument with array
std::cout << "key found. RegionName: " << strName << '\n';
}
else
{
std::cout << "key not found" << std::endl;
}
//METHOD 4
// create a JSON object
std::string strKey = "/Map/" + std::to_string(m_iRegionType);
// call find
auto it_two = conf_json.find(strKey.c_str());
if(true == (it_two != conf_json.end()))
{
std::cout << "Region key was found. RegionBucketName: " << *it_two << '\n';
std::string strRegionName = conf_json["Map"][m_iRegionType];
std::string strRegionName2 = *it_two;
std::cout << "strRegionName: " << strRegionName << '\n';
std::cout << "strRegionName2: " << strRegionName2 << '\n';
}
else
{
//getting this as OUTPUT even though key is available
std::cout << "invalid region type, key not available m_iRegionType: " << m_iRegionType << std::endl;
}
}
else
{
std::cout << "[ReadFileContents]Read Write Json object is empty" << std::endl;
}
}
I have also tried using the small json structure where I am not able to access the value using the runtime key.
json j =
{
{"integer", 1},
{"floating", 42.23},
{"string", "hello world"},
{"boolean", true},
{"object", {{"key1", 1}, {"key2", 2}}},
{"array", {1, 2, 3}}
};
int avail4 = j.value("/integer"_json_pointer, 444);
std::cout << "avail4 : " << avail4 << std::endl; //OUTPUT- avial4 : 1
int avail5 = j.value("/object/key2"_json_pointer, 555);
std::cout << "avail5 : " << avail5 << std::endl; //OUTPUT- avial5 : 2
auto strKey3 = "/object/key2";
int avail6 = j.value(strKey3, 666);
std::cout << "avail6 : " << avail6 << std::endl; //OUTPUT- avial6 : 666
Could any one help me.
You can't use ["Map"]["1"] to find the inner array objects. You need iterator through the array
A code example may like this:
#include <nlohmann/json.hpp>
#include <iostream>
// for convenience
using json = nlohmann::json;
int main() {
json j = R"(
{
"Version": 1.1,
"Size": 1024,
"integer": 600,
"Map": [{
"0": "india"
}, {
"1": "usa"
}, {
"2": "china"
}, {
"2": "japan"
}],
"name": "xxx"
}
)"_json;
for (const auto& ele : j["Map"]) {
if (ele.contains("1")) {
std::cout << ele["1"] << std::endl;
}
}
}
Output:
usa
Demo

Is this Knapsack-like algorithm correct?

I've implemented a simple algorithm for a Knapsack-like problem. I've searched other solutions in similar questions, but I cannot determine if my solution is complete for this specific problem.
The problem:
Write a function that takes a number a list of numbers. The function should return "true"
if number can be calculated using add and subtract operations or "false" otherwise.
Examples:
(9, [2,8,5,10]) -> true
(0, [4,3,2,1]) -> true
(0, []) -> true
(0, [1]) -> false
(1, [1]) -> true
(4, [1,2]-> false
From my understanding the algorithm must use all the numbers and should not stop in non-leaf nodes. So this is my code:
bool knapSack(int res, const std::vector<int>& v, int index, int cur_add)
{
bool ret = false;
if (index < v.size())
{
if (v.size() > 0)
{
ret = knapSack(res, v, index + 1, cur_add + v[index]);
if(!ret)
ret = knapSack(res, v, index + 1, cur_add - v[index]);
}
}
else if(res == cur_add)
ret = true;
return ret;
}
int main()
{
std::cout << "The result is: " << knapSack(9, { 5,8,10,2 }, 0, 0) << std::endl;
std::cout << "The result is: " << knapSack(0, { 4,3,2,1 }, 0, 0) << std::endl;
std::cout << "The result is: " << knapSack(0, { }, 0, 0) << std::endl;
std::cout << "The result is: " << knapSack(0, { 1 }, 0, 0) << std::endl;
std::cout << "The result is: " << knapSack(1, { 1 }, 0, 0) << std::endl;
std::cout << "The result is: " << knapSack(2, { 4,1 }, 0, 0) << std::endl;
return 0;
}
Is this algorithm complete and correct, or am I missing something?

How to traverse a map of the form pair<int,pair<int,int>> with a iterator

I defined map like
map <int,pair<int,int>> hmap;
If there is a pair(2,pair(3,4)) how to get 2 3 4 values, itr->first, itr->second not working
If there is a pair(2,pair(3,4)) how to get 2 3 4 values [from an iterator itr to map<int,pair<int, int>>]
I suppose
itr->first // 2
itr->second.first // 3
itr->second.second // 4
Here is a demonstrative program with using iterators and the range-based for statement.
#include <iostream>
#include <map>
int main()
{
std::map<int, std::pair<int, int>> hmap{ { 1, { 2, 3 } }, { 2, { 3, 4 } } };
for (auto it = hmap.begin(); it != hmap.end(); ++it)
{
std::cout << "{ " << it->first
<< ", { " << it->second.first
<< ", " << it->second.second
<< " } }\n";
}
std::cout << std::endl;
for (const auto &p : hmap)
{
std::cout << "{ " << p.first
<< ", { " << p.second.first
<< ", " << p.second.second
<< " } }\n";
}
std::cout << std::endl;
}
Its output is
{ 1, { 2, 3 } }
{ 2, { 3, 4 } }
{ 1, { 2, 3 } }
{ 2, { 3, 4 } }

finding wildcard entries efficiently

I have a map which contains strings as keys; those string resemble wildcards.
A key can have a * at the end, which means that when a lookup is performed, a string that has this key as a prefix shall match this key.
How can I efficiently retrieve the closest matching entry in such a map?
I tried sorting the map entries in a custom way and then using lower_bound, but that sorting does not produce the correct result:
#include <map>
#include <string>
#include <iostream>
#include <algorithm>
struct Compare {
bool operator()(const std::string& lhs, const std::string& rhs) const
{
if (lhs.size() < rhs.size()) {
return true;
}
if (lhs.size() > rhs.size()) {
return false;
}
bool isWildcardlhsAtEnd = (!lhs.empty() && lhs.back() == '*');
bool isWildcardrhsAtEnd = (!rhs.empty() && rhs.back() == '*');
if (isWildcardlhsAtEnd && isWildcardrhsAtEnd) {
return lhs < rhs;
}
auto lhSubString = lhs.substr(0, lhs.size() - 1);
auto rhsSubString = rhs.substr(0, rhs.size() - 1);
if (isWildcardlhsAtEnd || isWildcardrhsAtEnd) {
if (lhSubString == rhsSubString) {
return !isWildcardlhsAtEnd;
}
else {
return lhSubString < rhsSubString;
}
}
return lhs < rhs;
}
};
template <typename Map>
void lookup(const Map& map, const std::string& key, int expected)
{
auto it = map.lower_bound(key);
if (it != map.end()) {
std::cout << "found " << it->first << " for " << key << "; ";
std::cout << "expected: " << expected << " got: " << it->second << std::endl;
}
else {
std::cout << "did not find a match for " << key << std::endl;
}
}
int main()
{
std::map<std::string, int, Compare> map = {
{ "bar", 1 },
{ "bar*", 2 },
{ "foo1", 3 },
{ "bar1", 4 },
{ "bar1*", 5 },
{ "foo1*", 6 },
{ "bar12", 7 },
{ "bar12*", 8 },
{ "foo12", 9 },
{ "bar123", 10 },
{ "b*", 11 },
{ "f*", 12 },
{ "b", 13 },
{ "f", 14 }
};
std::cout << "sorted map \n------" << std::endl;
std::for_each(map.begin(), map.end(), [](const auto& e) { std::cout << e.first << std::endl; });
std::cout << "-------" << std::endl;
lookup(map, "foo1", 3);
lookup(map, "foo123", 6);
lookup(map, "foo", 12);
lookup(map, "bar1234", 8);
}
This produces the following output which demonstrates the incorrect lookup:
sorted map
------
b
f
b*
f*
bar
bar1
bar*
foo1
bar12
bar1*
foo12
foo1*
bar123
bar12*
-------
found foo1 for foo1; expected: 3 got: 3
did not find a match for foo123
found bar1 for foo; expected: 12 got: 4
did not find a match for bar1234
live example
I am also open to using another data structure if necessary.
If you separate the exact search and wildcard search, then the natural ordering works fine with strings. This code seems to produce the desired results (I think), and is efficient. The separate maps can be wrapped more conveniently of course.
#include <map>
#include <string>
#include <iostream>
#include <algorithm>
template <typename Map>
void lookup(const Map& exact ,const Map& wilds, const std::string& key, int expected)
{
auto it = exact.find(key);
if (it == exact.end()) { // if not exact match
it = wilds.lower_bound(key); // do best match
it--;
}
std::cout << "found " << it->first << " for " << key << "; ";
std::cout << "expected: " << expected << " got: " << it->second << std::endl;
}
int main()
{
std::map<std::string, int> wilds = {
{ "bar*", 2 },
{ "bar1*", 5 },
{ "foo1*", 6 },
{ "bar12*", 8 },
{ "b*", 11 },
{ "f*", 12 }
};
std::map<std::string, int> exact = {
{ "bar", 1 },
{ "foo1", 3 },
{ "bar1", 4 },
{ "bar12", 7 },
{ "foo12", 9 },
{ "bar123", 10 },
{ "b", 13 },
{ "f", 14 }
};
lookup(exact , wilds, "foo1", 3);
lookup(exact , wilds,"foo123", 6);
lookup(exact , wilds,"foo", 12);
lookup(exact , wilds,"bar1234", 8);
}

How to iterate through a map of vectors while deleting?

I have a map of vectors in C++. For each vector, I'd like to delete entries that meet a certain condition. If a vector ends up empty, I'd like to delete it from the map. I know deletion can mess up iterators, and doubly iterating makes this even more confusing for me. What's the best way to accomplish this?
The standard mutating container loop:
for (auto it = m.begin(); it != m.end(); )
{
// work
if (/* need to delete */) // e.g "if (it->second.empty())"
{
it = m.erase(it);
}
else
{
++it;
}
}
Here is a demonstrative program that shows how it can be done
#include <iostream>
#include <map>
#include <vector>
int main()
{
std::map<int, std::vector<int>> m =
{
{ 1, { 1, 2 } },
{ 2, { 2 } },
{ 3, { 3, 4 } },
{ 4, { 4 } }
};
for ( const auto &p : m )
{
std::cout << p.first << ": ";
for ( int x : p.second ) std::cout << x << ' ';
std::cout << std::endl;
}
for ( auto it = m.begin(); it != m.end(); )
{
it->second.erase( it->second.begin() );
if ( it->second.empty() ) it = m.erase( it );
else ++it;
}
std::cout << std::endl;
for ( const auto &p : m )
{
std::cout << p.first << ": ";
for ( int x : p.second ) std::cout << x << ' ';
std::cout << std::endl;
}
return 0;
}
The program output is
1: 1 2
2: 2
3: 3 4
4: 4
1: 2
3: 4