This question already has answers here:
A std::map that keep track of the order of insertion?
(15 answers)
Closed 10 years ago.
I have the following code:
#include <iostream>
#include "boost/unordered_map.hpp"
using namespace std;
using namespace boost;
int main()
{
typedef unordered_map<int, int> Map;
typedef Map::const_iterator It;
Map m;
m[11] = 0;
m[0] = 1;
m[21] = 2;
for (It it (m.begin()); it!=m.end(); ++it)
cout << it->first << " " << it->second << endl;
return 0;
}
However, I am looking for something that preserves the order so that later I can iterate over the elements in the same order in which they were inserted. On my computer the above code does not preserve the order, and prints the following:
0 1
11 0
21 2
I thought maybe I could use a boost::multi_index_container
typedef multi_index_container<
int,
indexed_by<
hashed_unique<identity<int> >,
sequenced<>
>
> Map;
Can somebody show me how to implement my original code using this container (or any other appropriate container) so that the iterator follows the order of insertion?
#include <iostream>
#include "boost/unordered_map.hpp"
#include <boost/multi_index_container.hpp>
#include <boost/multi_index/member.hpp>
#include <boost/multi_index/ordered_index.hpp>
#include <boost/multi_index/hashed_index.hpp>
#include <boost/multi_index/sequenced_index.hpp>
using namespace std;
using namespace boost;
using namespace boost::multi_index;
struct key_seq{};
struct key{};
struct Data_t
{
int key_;
int data_;
Data_t (int key_v, int data_v) : key_(key_v), data_(data_v) {}
};
int main()
{
typedef multi_index_container<
Data_t,
indexed_by<
hashed_unique<tag<key>, BOOST_MULTI_INDEX_MEMBER(Data_t,int,key_)>,
sequenced<tag<key_seq> >
>
> Map;
typedef Map::const_iterator It;
typedef index<Map,key>::type Map_hashed_by_key_index_t;
typedef index<Map,key>::type::const_iterator Map_hashed_by_key_iterator_t;
typedef index<Map,key_seq>::type Map_sequenced_by_key_index_t;
typedef index<Map,key_seq>::type::const_iterator Map_sequenced_by_key_iterator_t;
Map m;
m.insert(Data_t(11,0));
m.insert(Data_t(0,1));
m.insert(Data_t(21,1));
{
cout << "Hashed values\n";
Map_hashed_by_key_iterator_t i = get<key>(m).begin();
Map_hashed_by_key_iterator_t end = get<key>(m).end();
for (;i != end; ++i) {
cout << (*i).key_ << " " << (*i).data_ << endl;
}
}
{
cout << "Sequenced values\n";
Map_sequenced_by_key_iterator_t i = get<key_seq>(m).begin();
Map_sequenced_by_key_iterator_t end = get<key_seq>(m).end();
for (;i != end; ++i) {
cout << (*i).key_ << " " << (*i).data_ << endl;
}
}
return 0;
}
You can try creating an ordered map using the combination of map and the vector.
Vector can hold the pair of key and
value.
Vector iterator can be used as
iterator to traverse ordered map.
map can be used access the elements
faster.
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;
}
As one can access the shared memory object using boost's find method of managed_shared_memory, like:
res = segment.find<MyType> ("name");
Is there a way to list the names of all shared memory objects defined in a certain segment? I need it for debugging but didn't find boost API for that.
You can use the named_begin() and named_end() iterators.
A small demo that creates various vectors of strings with random lengths and reports back how many it found:
Live On Coliru
#include <boost/interprocess/managed_mapped_file.hpp>
#include <boost/interprocess/containers/string.hpp>
#include <boost/interprocess/containers/vector.hpp>
#include <boost/container/scoped_allocator.hpp>
#include <iostream>
#include <vector>
namespace bip = boost::interprocess;
using Mem = bip::managed_mapped_file;
template <typename T = void>
using Alloc = boost::container::scoped_allocator_adaptor<
bip::allocator<T, Mem::segment_manager> >;
using String = boost::container::basic_string<char, std::char_traits<char>, Alloc<char> >;
template <typename T>
using Vector = boost::container::vector<T, Alloc<T> >;
int main() {
auto mf = Mem(bip::open_or_create, "test.bin", 20ul<<30);
std::cout << "Named #" << mf.get_segment_manager()->get_num_named_objects() << "\n";
using Container = Vector<String>;
for (auto to_create: {"foo", "bar", "qux"}) {
auto& c = *mf.find_or_construct<Container>(to_create)(mf.get_segment_manager());
auto n = rand()%10;
for (int i = 0; i<n; ++i) {
c.emplace_back(std::to_string(i*i));
}
}
std::cout << "Named #" << mf.get_segment_manager()->get_num_named_objects() << "\n";
for (auto it = mf.named_begin(); it != mf.named_end(); ++it) {
std::string_view name(it->name(), it->name_length());
std::cout << "Item " << name << " has " <<
reinterpret_cast<Container const*>(it->value())->size() << " elements\n";
}
}
Prints
Named #0
Named #3
Item bar has 6 elements
Item foo has 3 elements
Item qux has 7 elements
Of course, I don't encourage using the reinterpret_cast. Use the find_or_construct interface like you would normally.
This question already has answers here:
std::map - how to change key sorting?
(4 answers)
Closed 7 years ago.
I have a map with string date-time keys, and int values. I would like to sort my map by the date and time (by the map keys actually) which are in format like this: 30/11/2012:13:49:55. Is that possible? How to sort them? When sorting only string there's no such a big deal, but I really don't know how to do this with date/time string.
#include <iostream>
#include <string>
#include <map>
using namespace std;
int main()
{
map<string, int> mymap;
mymap["30/11/2012:13:49:09"] = 122;
mymap["30/11/2012:13:49:55"] = 100;
mymap["30/11/2012:13:49:12"] = 123;
mymap["29/11/2012:19:26:11"] = 45;
for (std::map<string, int>::iterator i = mymap.begin(); i != mymap.end(); i++)
{
cout << i->first << "\n";
}
};
The output of the program suggests that this map is already ordered, however, I'm not quite sure if it always (in every case) sort it like I want it to.
Ok folks, will something like this work fine?
#include <iostream>
#include <string>
#include <cstdlib>
#include <cstring>
#include <ctime>
using namespace std;
time_t string_to_time_t(string s)
{
struct tm tmp;
time_t t;
memset(&tmp, 0, sizeof(struct tm));
strptime(s.c_str(), "%d/%m/%Y:%H:%M:%S", &tmp);
t = mktime(&tmp);
return t;
}
int main()
{
time_t t, u;
t = string_to_time_t("30/11/2012:13:49:09");
u = string_to_time_t("30/11/2012:13:49:08");
if (u>t)
{
cout << "true" << endl;
}
else if (u==t)
{
cout << "same" << endl;
}
else
{
cout << "false" << endl;
}
return 0;
}
EDIT:
Huh, it seems to work now, thanks!
#include <iostream>
#include <string>
#include <cstdlib>
#include <cstring>
#include <ctime>
#include <map>
using namespace std;
time_t string_to_time_t(string s)
{
struct tm tmp;
time_t t;
memset(&tmp, 0, sizeof(struct tm));
strptime(s.c_str(), "%d/%m/%Y:%H:%M:%S", &tmp);
t = mktime(&tmp);
return t;
}
int main()
{
map<time_t, int> mymap;
mymap[string_to_time_t("30/11/2012:13:49:09")] = 122;
mymap[string_to_time_t("30/11/2012:13:49:55")] = 100;
mymap[string_to_time_t("30/11/2012:13:49:12")] = 123;
mymap[string_to_time_t("29/11/2012:19:26:11")] = 45;
for (std::map<time_t, int>::iterator i = mymap.begin(); i != mymap.end(); i++)
{
cout << i->first << " " << i->second << "\n";
}
};
You can provide your own functor as a template argument when instantiating your map, cf. std::map - how to change key sorting?. The sort functor should parse the string and give the proper relations.
That said, I am a big fan of date strings whose alphabetical order is the same as their logical one, e.g. 2015-12-31-23-59-49.999 or such (for 11.59 pm plus a few sconds on new year's eve). I use such strings when I name pictures and when I print to log files.
I have a map like this:
map<string, map<int, int>> collector;
And I have no idea how to insert data in my map. If I had
map<string, int> collector;
with only key-value I would use
collector.insert(pair<string, int>)(name,money));
But what is the way of inserting when we have map in map. I tried to do:
typedef map<int, int> map_;
for(iteration = collector.begin(); iteration != collector.end(); iteration++) {
iteration = collector.find(word);
if(iteration == collector.end()) {
iteration = collector.insert(map_::value_type(num,num).first;
}
}
This way is not working for me.
Here are some ways to insert into your data structure:
#include <iostream> // cout
#include <map>
#include <string>
#include <utility> // make_pair
using namespace std;
int main()
{
using Collector = map<string, map<int, int>>;
Collector collector;
collector["USD"] = Collector::mapped_type{ { 1, 3 }, { 0, 8 } };
collector["EUR"].insert(make_pair(4, 5));
collector["EUR"].insert(make_pair(6, 7));
collector["CHF"][2] = 4;
const Collector::mapped_type jpyIntegers { { 10, 20 }, { 100, 200 } };
collector.insert(make_pair("JPY", jpyIntegers));
collector["MMK"];
for (const auto& a: collector) {
cout << a.first << ": ";
for (const auto& i: a.second) {
cout << "(" << i.first << "|" << i.second << ")";
}
cout << "\n";
}
}
I am using boost::multi_index with a data type I'd like to index based on its size. However, the size() member function of this data type is expensive to execute. Does multi_index cache the values it gets from its key extractors?
For example, if I created a multi_index container with an ordered index with a member function key (element.size()), and inserted an element whose size put it somewhere in the middle of the container, would the container re-invoke the size() member function on all the elements it visits while traversing its internal data structure before finding the right insertion point?
Well, the documentation for member function indexers says they call the referenced member function: http://www.boost.org/doc/libs/1_46_0/libs/multi_index/doc/reference/key_extraction.html#key_extractors
But when in doubt, profile:
#include <boost/multi_index_container.hpp>
#include <boost/multi_index/mem_fun.hpp>
#include <boost/multi_index/indexed_by.hpp>
#include <boost/multi_index/hashed_index.hpp>
#include <boost/multi_index/ordered_index.hpp>
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
namespace bmi = boost::multi_index;
int g_calls = 0;
struct A
{
explicit A(int sz) : m_size(sz) { }
int size() const { ++g_calls; return m_size; }
private:
int m_size;
};
typedef boost::multi_index_container<
A*,
bmi::indexed_by<
bmi::ordered_non_unique<
BOOST_MULTI_INDEX_CONST_MEM_FUN(A,int,A::size)
>
>
> container_t;
int main()
{
container_t cont;
int n = 100;
vector<int> o(2*n+1);
for( int i = 0; i != 2*n+1; ++i )
o[i] = i;
random_shuffle(o.begin(), o.end());
for( int i = 0; i != n; ++i )
cont.insert(new A(o[i]));
cout << "Calls to A::size(): "<< g_calls << endl;
for( int i = n+1; i <= 2*n; ++i )
cont.insert(new A(o[i]));
cout << "Calls to A::size(): "<< g_calls << endl;
cont.insert(new A(o[n]));
cout << "Calls to A::size(): "<< g_calls << endl;
for( int i = 0; i != o.size(); ++i )
cont.find(o[i]);
cout << "Calls after calling find " << o.size() << " times: "<< g_calls << endl;
return 0;
}
Gives the following output (using Boost 1.46):
Calls to A::size(): 629
Calls to A::size(): 1465
Calls to A::size(): 1474
Calls after calling find 201 times: 3262
So, it appears the answer is no, it doesn't cache values.