finding wildcard entries efficiently - c++

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);
}

Related

How to display a map of a map (C++)?

I made the following map to store data from a .log :
map<string,pair(int,map<string,int>)>.
I manage to store the data but not to retrieve it. What I do is:
cout<< "first string: "<< debut->first
<< " pair (first int): " << debut->second.first << endl;
(debut is a constant iterator of a map)
With that I get the first string and the int of the pair, but I don't know how to get the content of the map. I tried different syntaxes as debut->second.second->first or debut->second.second.first but of them work.
Does someone have an idea?
I don't know how to get the content of the map.
You can print out the content of the innermost map as shown below([DEMO]):
auto beg = debut->second.second.cbegin();
auto end = debut->second.second.cend();
while(beg!=end) //can also use for loop
{
std::cout<<beg->first<<" ";
std::cout<<beg->second<<std::endl;
++beg;
}
Here is a more complete example for printing the all the content of the maps, just for demonstration:
#include <iostream>
#include <map>
int main()
{
std::map<std::string,std::pair<int,std::map<std::string,int>>> m{ { "first", { 5, {{"a", 10}, {"b", 20}} }} ,
{ "second", { 6, {{"c", 100}, {"d", 200},{"e", 300} }}},
{ "third", { 7, {{"f", 400}} } }};
//////////////////////////////////////////////////////////////////
//PRINTING THE CONTENT OF THE MAP
auto debutBegin = m.cbegin(); //const iterator to beginning of outer map
auto debutEnd = m.cend(); //const iterator to end of outer map
while(debutBegin!=debutEnd)
{
auto beg = debutBegin->second.second.cbegin(); //const iterator to beginning of inner map
auto end = debutBegin->second.second.cend();//const iterator to end of inner map
std::cout<<debutBegin->first<<" ---- "<<debutBegin->second.first<<std::endl;
while(beg!=end)
{
std::cout<<beg->first<<" ";
std::cout<<beg->second<<std::endl;
++beg;
}
debutBegin++;
}
return 0;
}
Output
The output of the above program is:
first ---- 5
a 10
b 20
second ---- 6
c 100
d 200
e 300
third ---- 7
f 400
You probably need to iterate over the second map as well. Here's one way to do this:
map<string,pair<int,map<string,int>>> mp1;
map<string, int> mp2;
mp2["str2 inside mp1"] = 1;
mp1["str1 (key)"] = {2, mp2};
for(auto pair1 : mp1) {
cout << "First string: " << pair1.first << "\n"; // str1 (key)
cout << "First int: " << pair1.second.first << "\n"; // First int: 2
for(auto pair2 : pair1.second.second) {
cout << "Second string: " << pair2.first << "\n"; // Second string: str2 inside mp1
cout << "Second int: " << pair2.second << "\n"; // Second int: 1
}
}
However (as the comments suggest) this is a complicated approach, maybe you need to submit a new question explaining your usecase. My thought would be to seperate this into to seperate maps somehow.
I would recommend to:
split your printing into functions,
print one map at a time, and
use whatever number of variables/references you need to make your code clearer.
The code below is just an example that tries to follow that intent.
[Demo]
#include <iostream> // cout
#include <map>
#include <string>
#include <utility> // pair
using inner_map_t = std::map<std::string, int>;
using outer_map_t = std::map<std::string, std::pair<int, inner_map_t>>;
std::ostream& operator<<(std::ostream& os, const inner_map_t& m)
{
os << "\t{\n";
bool first_elem{true};
for (auto& [key, value] : m)
{
auto& second_string{ key };
auto& second_int{ value };
os
<< "\t\t" << (first_elem ? "" : ", ") << "second string: " << second_string << ", "
<< "second int: " << second_int << "\n";
first_elem = false;
}
os << "\t}\n";
return os;
}
std::ostream& operator<<(std::ostream& os, const outer_map_t& m)
{
os << "{\n";
bool first_elem{ true };
for (auto& [key, value] : m)
{
auto& first_string{ key };
auto& first_int{ value.first };
auto& inner_map{ value.second };
os
<< "\t" << (first_elem ? "" : ", ") << "first string: " << first_string << ", "
<< "first int: " << first_int << "\n"
<< inner_map;
first_elem = false;
}
os << "}\n";
return os;
}
int main()
{
const outer_map_t m{
{ "one", { 1, {{"uno", 10}, {"cien", 100}} } },
{ "two", { 2, {{"dos", 20}} } },
{ "three", { 3, {{"tres", 30}} } }
};
std::cout << m << "\n";
}
// Outputs:
//
// {
// first string: one, first int: 1
// {
// second string: cien, second int: 100
// , second string: uno, second int: 10
// }
// , first string: three, first int: 3
// {
// second string: tres, second int: 30
// }
// , first string: two, first int: 2
// {
// second string: dos, second int: 20
// }
// }
And another implementation, probably a bit neater.
[Demo]
#include <iostream> // cout
#include <map>
#include <string>
#include <utility> // pair
using inner_map_t = std::map<std::string, int>;
using pair_t = std::pair<int, inner_map_t>;
using outer_map_t = std::map<std::string, pair_t>;
template <typename T, typename U>
std::ostream& print_map(std::ostream& os, const std::map<T,U> m, size_t level_of_indent)
{
std::string indent(4*level_of_indent, ' ');
std::string next_indent(4*(level_of_indent + 1), ' ');
os << "{\n";
bool first{ true };
for (auto& [key, value] : m)
{
os << (first ? "" : ",\n") << next_indent << "'" << key << "' : " << value;
first = false;
}
os << "\n" << indent << "}";
return os;
}
std::ostream& operator<<(std::ostream& os, const inner_map_t& m) {
return print_map(os, m, 1);
}
std::ostream& operator<<(std::ostream& os, const pair_t& p) {
return os << "(" << p.first << ", " << p.second << ")";
}
std::ostream& operator<<(std::ostream& os, const outer_map_t& m) {
return print_map(os, m, 0);
}
int main()
{
const outer_map_t m{
{ "Alien", { 1, {{"speed", 90}, {"power", 90}} } },
{ "Jabba", { 2, {{"speed", 10}} } },
{ "T1000", { 3, {{"speed", 70}} } }
};
std::cout << m << "\n";
}
// Outputs:
//
// {
// 'Alien' : (1, {
// 'power' : 90,
// 'speed' : 90
// }),
// 'Jabba' : (2, {
// 'speed' : 10
// }),
// 'T1000' : (3, {
// 'speed' : 70
// })
// }

How to use a vector variants as key in unordered_map?

How can I use a vector of variants as the key in unordered_map?
For example, I'd like to make the following code work.
using VariantType = std::variant<int, std::string, unsigned int>;
using VecVariantType = std::vector<VariantType>;
std::unordered_map<VecVariantType, int, $some_hash_function$> m;
How do I implement $some_hash_function$?
I enjoy a good terrible idea...
I have no idea how or why you would use something like this for something other than a "I wonder if I can get this to compile and run" example.
#include <iostream>
#include <vector>
#include <unordered_map>
#include <variant>
using VariantType = std::variant<int, std::string, unsigned int>;
using VecVariantType = std::vector<VariantType>;
struct Hasher
{
size_t operator()(const VecVariantType &v) const
{
size_t hash = 0;
for (auto &val : v)
{
hash ^= std::hash<VariantType>()(val);
}
return hash;
}
};
std::ostream& operator<<(std::ostream& out, std::pair<const VecVariantType, int> &p)
{
out << "key: { ";
bool needs_comma = false;
for (auto &var : p.first)
{
if (needs_comma)
{
out << ", ";
}
if (std::holds_alternative<int>(var))
{
out << "int: " << std::get<int>(var);
needs_comma = true;
}
if (std::holds_alternative<std::string>(var))
{
out << "string: " << std::get<std::string>(var);
needs_comma = true;
}
if (std::holds_alternative<unsigned int>(var))
{
out << "uint: " << std::get<unsigned int>(var);
needs_comma = true;
}
}
out << " }, value: " << p.second;
return out;
}
void lookup(const VecVariantType &var, std::unordered_map<VecVariantType, int, Hasher> &m)
{
std::cout << "Lookup ";
auto it = m.find(var);
if (it != m.end())
{
std::cout << "success - " << *it << "\n";
}
else
{
std::cout << "failure\n";
}
}
int main()
{
std::unordered_map<VecVariantType, int, Hasher> m;
auto one = VecVariantType { 1, "one", 1u };
auto two = VecVariantType { 2, "two", 2u };
auto three = VecVariantType { 3, "three", 3u };
auto nnn = VecVariantType { 1, "one", 1u, 2, "two", 2u, 3, "three", 3u };
m.emplace(one, 1);
m.emplace(two, 2);
m.emplace(three, 3);
m.emplace(nnn, 999);
std::cout << "Enumerating:\n";
for (auto& item : m)
{
std::cout << " " << item << "\n";
}
lookup(one, m);
lookup(two, m);
lookup(three, m);
lookup(nnn, m);
}
https://repl.it/repls/AmazingCrushingOpen64

reading nested json file w/ boost

I'm trying to read a JSON formatted file which is nested with the BOOST library in C++.
I tried a couple of things, browsed through many questions in this forum, but I couldn't find anything really similar, or that would work.
the json file im looking at has the following structure
{
"ABC": {
"FF:[10.0,20.0]": {
"GHG:[-2.5,-2.0]": {
"value": 1.1176470518112183,
"error": 0.013857235087295462
},
"GHG:[1.566,2.0]": {
"value": 0.9958805441856384,
"error": 0.027176504445043704
}
},
"FF:[30.0,50.0]": {
"GHG:[-2.5,-2.0]": {
"value": 1.1176470518112183,
"error": 0.013857235087295462
},
"GHG:[2.0,2.5]": {
"value": 1.0464363098144531,
"error": 0.061588554028766326
}
}
},
"ZXY": {
"FF:[10.0,20.0]": {
"GHG:[-2.5,-2.0]": {
"value": 1.1176470518112183,
"error": 0.013857235087295462
},
"GHG:[1.566,2.0]": {
"value": 0.9958805441856384,
"error": 0.027176504445043704
}
},
"FF:[30.0,50.0]": {
"GHG:[-2.5,-2.0]": {
"value": 1.1176470518112183,
"error": 0.013857235087295462
},
"GHG:[2.0,2.5]": {
"value": 1.0464363098144531,
"error": 0.061588554028766326
}
}
}
}
i was trying to use the BOOST_FOREACH method as is described here:
http://www.ce.unipr.it/people/medici/boost_ptree.html
#include <boost/property_tree/json_parser.hpp>
#include <boost/property_tree/ptree.hpp>
#include <boost/foreach.hpp>
#include <iostream>
namespace pt = boost::property_tree;
pt::ptree tree;
int main() {
pt::read_json("bla.json", tree);
BOOST_FOREACH( pt::ptree::value_type const&v, tree.get_child("ABC") ) {
const std::string & key = v.first;
const pt::ptree & subtree = v.second;
//const pt::ptree & subsubtree = v.second;
std::cout << key << std::endl;
if(subtree.empty()) {
std::cout << "subtree empty" << std::endl;
} else {
std::cout << "subtree not empty" << std::endl;
BOOST_FOREACH( pt::ptree::value_type const&sv, subtree.get_child(key) ) {
const std::string & subkey = sv.first; // key
const pt::ptree & subsubtree = sv.second; // value (or a subnode)
if(subsubtree.empty()) {
std::cout << "subsubtree empty" << std::endl;
} else {
std::cout << "subsubtree not empty" << std::endl;
std::cout << subsubtree.data() << std::endl;
}
}
}
}
return 0;
}
but i always get an error that there's no such node:
terminate called after throwing an instance of 'boost::wrapexcept<boost::property_tree::ptree_bad_path>'
what(): No such node (FF:[10.0,20.0])
Aborted
i'm pretty sure this is not a hard problem, but i'm kind of a newbie with c++ and i really appreciate any help!
Finally, I got it that your get_child usage is not correct! Just pass the tree to range-based for.
#include <boost/property_tree/json_parser.hpp>
#include <boost/property_tree/ptree.hpp>
#include <boost/foreach.hpp>
#include <iostream>
namespace pt = boost::property_tree;
pt::ptree tree;
int main() {
pt::read_json("bla.json", tree);
for(auto&& v : tree.get_child("ABC")) {
const std::string & key = v.first; // key
const pt::ptree & subtree = v.second; // value (or a subnode)
//const pt::ptree & subsubtree = v.second; // value (or a subnode)
std::cout << key << std::endl;
if(subtree.empty()) {
// This is a key:value
// use subtree.data() as string value or subtree.get_value<T>()
std::cout << "subtree empty" << std::endl;
} else {
// This is a subtree
// use subtree as child
std::cout << "subtree not empty" << std::endl;
for(auto&& sv : subtree/*.get_child(pt::path(key, '\0'))*/) {
[[maybe_unused]]const std::string & subkey = sv.first; // key
const pt::ptree & subsubtree = sv.second; // value (or a subnode)
std::cout << subkey << std::endl;
if(subsubtree.empty()) {
std::cout << "subsubtree empty" << std::endl;
} else {
std::cout << "subsubtree not empty" << std::endl;
std::cout << subsubtree.data() << std::endl;
for(auto&& ssv: subsubtree) {
[[maybe_unused]]const std::string & subsubkey = ssv.first; // key
const pt::ptree & subsubsubtree = ssv.second; // value (or a subnode)
std::cout << subsubkey << std::endl;
if(subsubsubtree.empty()) {
std::cout << "subsubsubtree empty" << std::endl;
if (auto subsubsubtree_v = subsubsubtree.get_value_optional<double>()) {
std::cout << subsubsubtree_v.get() << std::endl;
}
}
else {
std::cout << "subsubtree not empty" << std::endl;
std::cout << subsubtree.data() << std::endl;
}
}
}
}
}
}
return 0;
}
https://wandbox.org/permlink/uRub7N5VeZ9WrDKd

Two [or more] containers with same underlying data, but different views on the data

MyClass below represents a data structure that I need to be able to search very fast in two ways. So say I store the MyClass in and std::vector so that similar names in it can be quickly deleted and inserted continuously. But, I also need to be able to sort the contents of MyClass based on anInt. That is where an intrusive container (or Multimap) would sort the contents of a [very likely] unsorted std::vector. Two containers performing two very different duties on the same underlying items. Also, if I deleted the items from the std::vector they would also automatically disappear from the intrusive container.
Here is sort of the idea
#include <vector>
#include <iostream>
#include <vector>
#include <functional>
#include <boost/intrusive/unordered_set.hpp>
namespace bic = boost::intrusive;
std::hash<std::string> hash_fn;
struct MyClass : bic::unordered_set_base_hook<bic::link_mode<bic::auto_unlink>>
{
std::string name;
int anInt1;
mutable bool bIsMarkedToDelete;
MyClass(std::string name, int i) : name(name), anInt1(i), bIsMarkedToDelete(false) {}
bool operator==(MyClass const& o) const
{
return anInt1 == o.anInt1; // need the items in the intrusive container to sort on number
}
struct hasher
{
size_t operator()(MyClass const& o) const
{
//return hash_fn(o.name);
return o.anInt1; // need the items in the intrusive container to sort on number
}
};
};
std::ostream& operator << (std::ostream& out, const MyClass& ac)
{
out << ac.name << " " << ac.anInt1;
return out;
}
typedef bic::unordered_set<MyClass, bic::hash<MyClass::hasher>, bic::constant_time_size<false> > HashTable;
int main()
{
std::vector<MyClass> values
{
MyClass { "John", 0 },
MyClass { "Mike", 0 },
MyClass { "Dagobart", 25 },
MyClass { "John", 5 },
MyClass { "Mike", 25 },
MyClass { "Dagobart", 26 },
MyClass { "John", 10 },
MyClass { "Mike", 25 },
MyClass { "Dagobart", 27 },
MyClass { "John", 15 },
MyClass { "Mike", 27 }
};
HashTable::bucket_type buckets[100];
HashTable hashtable(values.begin(), values.end(), HashTable::bucket_traits(buckets, 100));
std::cout << "\nContents of std::vector<MyClass> values\n";
for(auto& e: values)
std::cout << e << " ";
std::cout << "\nContents of HashTable hashtable\n";
for(auto& b : hashtable)
std::cout << b << '\n';
std::cout << "\nContents of HashTable hashtable\n";
for(auto& b : hashtable)
std::cout << b << '\n';
#if 0 // This code won't compile since there is no operator [] for hashtable
for(int bucket = 0; bucket < 27; bucket++)
{
auto hit(hashtable[bucket].rbegin());
auto hite(hashtable[bucket].rend());
while (hit != hite)
{
MyClass mc = *hit;
std::cout << mc << " ";
hit++;
}
std::cout << '\n';
}
#endif // 0
std::cout << '\n';
std::cout << "values size first " << values.size() << '\n';
std::cout << "hash size fist " << hashtable.size() << '\n';
for(auto& e: values)
e.bIsMarkedToDelete |= ("Mike" == e.name);
std::cout << "removing all bIsMarkedToDelete";
for(auto& e: values)
if(e.bIsMarkedToDelete)
std::cout << e << " ";
std::cout << '\n';
// Note how easy and performance fast it is to delete items from the std::vector view
// I need the intrsive view to automatically update as well
values.erase(
std::remove_if(std::begin(values), std::end(values), std::mem_fn(&MyClass::bIsMarkedToDelete)),
std::end(values));
#if 0 // This code won't compile since there is no operator [] for hashtable
// If I did this now, it should show the "Mike" itens gone and the
/// rest of the items hanging off the same bucket still there.
for(int bucket = 0; bucket < 27; bucket++)
{
auto hit(hashtable[bucket].rbegin());
auto hite(hashtable[bucket].rend());
while (hit != hite)
{
MyClass mc = *hit;
std::cout << mc << " ";
hit++;
}
std::cout << '\n';
}
#endif // 0
std::cout << "values size now " << values.size() << '\n';
std::cout << "hash size now " << hashtable.size() << '\n';
std::cout << "Contents of value after removing elements " << '\n';
for(auto& e: values)
std::cout << e << " ";
std::cout << '\n';
values.clear();
std::cout << values.size() << '\n';
std::cout << hashtable.size() << '\n';
std::cout << "Done\n";
int j;
std::cin >> j;
}
You need fast lookups using different indices. This makes me think of Boost MultiIndex.
Next:
So say I store the MyClass in and std::vector so that similar names in it can be quickly deleted and inserted continuously
combined with
Also, if I deleted the items from the std::vector they would also automatically disappear
makes it clear you cannot escape the cost of keeping all indices up to date anyways. In which case, Boost Multi Index is as good as it gets.
Here's a sample:
Live On Coliru
#include <iostream>
#include <vector>
#include <boost/tuple/tuple_comparison.hpp>
#include <boost/range/iterator_range.hpp>
#include <boost/multi_index_container.hpp>
#include <boost/multi_index/member.hpp>
#include <boost/multi_index/random_access_index.hpp>
#include <boost/multi_index/hashed_index.hpp>
#include <boost/multi_index/ordered_index.hpp>
namespace bmi = boost::multi_index;
struct MyClass
{
std::string name;
int anInt1;
MyClass(std::string name, int i) : name(name), anInt1(i) {}
//bool operator==(MyClass const& o) const { return boost::tie(name, anInt1) == boost::tie(o.name, o.anInt1); }
//bool operator< (MyClass const& o) const { return boost::tie(name, anInt1) < boost::tie(o.name, o.anInt1); }
friend std::ostream& operator << (std::ostream& out, const MyClass& ac) {
return out << ac.name << " " << ac.anInt1;
}
};
using Table = bmi::multi_index_container<MyClass,
bmi::indexed_by<
bmi::random_access<bmi::tag<struct as_vector> >,
bmi::ordered_non_unique<bmi::tag<struct by_number>,
bmi::member<MyClass, int, &MyClass::anInt1>
>,
bmi::hashed_non_unique<bmi::tag<struct by_name>,
bmi::member<MyClass, std::string, &MyClass::name>
>
>
>;
void alternative_remove_mikes(Table& values);
int main()
{
Table values {
{ "John", 0 },
{ "Mike", 0 },
{ "Dagobart", 25 },
{ "John", 5 },
{ "Mike", 25 },
{ "Dagobart", 26 },
{ "John", 10 },
{ "Mike", 25 },
{ "Dagobart", 27 },
{ "John", 15 },
{ "Mike", 27 },
};
auto& name_idx = values.get<by_name>();
std::cout << "\nBEFORE: Ordered by number:\n";
for(auto& e: values.get<by_number>())
std::cout << e << "\n";
std::cout << "\nBEFORE: O(1) lookup by name:\n";
for(auto& e : boost::make_iterator_range(name_idx.equal_range("Mike")))
std::cout << e << '\n';
std::cout << "removing all Mikes\n";
name_idx.erase("Mike");
// alternative_remove_mikes(values);
std::cout << "\nAFTER: Ordered by number:\n";
for(auto& e: values.get<by_number>())
std::cout << e << "\n";
std::cout << "\nAFTER: O(1) lookup by name:\n";
for(auto& e : boost::make_iterator_range(name_idx.equal_range("Mike")))
std::cout << e << '\n';
values.clear();
std::cout << "Done\n----------------------------\n";
}
If you want to keep the code to remove similar to the code you had (which is not optimal, but hey, just in case):
void alternative_remove_mikes(Table& values) {
// this uses the same `remove_if` approach together with the `rearrange()` feature of `random_access` index
std::vector<boost::reference_wrapper<MyClass const> > refs(values.begin(), values.end());
// remove_if is not good enough since it will leave the removed end unspecified
auto it = std::partition(refs.begin(), refs.end(), [](MyClass const& mc) { return "Mike" != mc.name; });
std::cout << "Removing " << std::distance(it, refs.end()) << " items:\n";
values.rearrange(refs.begin());
auto newend = values.begin() + std::distance(refs.begin(), it);
for (auto& e : boost::make_iterator_range(newend, values.end()))
std::cout << " -- removing " << e << "\n";
values.erase(newend, values.end());
}
Output:
BEFORE: Ordered by number:
John 0
Mike 0
John 5
John 10
John 15
Dagobart 25
Mike 25
Mike 25
Dagobart 26
Dagobart 27
Mike 27
BEFORE: O(1) lookup by name:
Mike 27
Mike 25
Mike 25
Mike 0
removing all Mikes
AFTER: Ordered by number:
John 0
John 5
John 10
John 15
Dagobart 25
Dagobart 26
Dagobart 27
AFTER: O(1) lookup by name:
Done
----------------------------

Initialize a map with map-values

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;
}