I need a container of unique elements to be accessed with a triplet of int, and each int can be over 1.000.000.000.
(Only few of these elements will be actually filled, and actually these elements are boost::unordered_map themselves).
Is it faster to have a multiindex array like boost::multiindex (or maybe something else I don't know) or just a boost::unordered_map with a composed string as a key ?
Multi-index isn't what you want, you seem to want a single index whose type is a triple. (Unless you actually do want three independent indexes; if I misunderstood, leave a comment.)
Don't use strings, heavens no. Just use the triple as a key:
typedef std::tuple<int, int, int> key_type;
If you use an std::map<key_type, T>, you get logarithmic lookup, which may be sufficient, and I think you don't even have to do any more work (not sure if lexicographic comparison is defined by default for tuples).
If you want to use an std::unordered_map<key_type, T> (or the boost version), you have to define a hash function. Boost already has one for tuples, I think, but C++11 doesn't; but it's very easy to implement yourself based on hash_combine() which you can just crop out off the Boost code.
Related
As far as I looked through the C++ reference, there is no function which returns a vector (or similar) containing all the keywords of a map. Why is this so? This is not a super important function, but sometimes it can be useful. (I don't exactly understand the key_comp function, but this seems to be not what I'm looking for)
Just for completeness, here is some function which does what I want:
template<typename key_t, typename value_t>
std::vector<key_t> getKeywords(const std::map<key_t, value_t>& m){
std::vector<key_t> keywords;
for(const auto& it: m){
keywords.push_back(it.first);
}
return keywords;
}
This is for the same reason that there is no operator+ for std::list iterators.
The standard tries not to encourage inefficient operations, in preference for you choosing the appropriate container for the job.
Creating a vector of all map keys is non-trivial because such a vector is not maintained internally along with the map.
You can of course create it if you really want, as you've already shown. But the standard wants you to know that you probably should be looking for another approach.
For example, if you just want to iterate over the keys, you can iterate over the whole map instead and use only the first part of each resultant pair.
Also, the standard library is intended to give you building blocks, not to suit every possible use case imaginable.
The two chief reasons are that most implementations do not have a vector of keywords intenally, so they would have to create it on the fly. And as you can see, creating it isn't really hard so there is little need to have it in the Standard,
Indeed, the keys are not accessible as such because the concern of the map class is O(log(N)) retrieval, not iteration.
As a general guideline when using the stl, choose your containers according to the use case of your application. If you want fast iteration, you can use a vector of tuple<Key, Value> and sort it, or use a pair<vector<Key>, vector<Value>> that you keep sorted by hand. std::make_heap and the like can be handy for this approach.
Retrieving the map keys can be done like your implementation.
Given an iterator, is it possible to retrieve/use the correct comparison function for the collection that this iterator refers to?
For example, let's assume I'm writing a generic algorithm:
template <class InIt, class T>
void do_something(InIt b, InIt e, T v) {
// ...
}
Now, let's say I want to do something simple, like find v in [b..e). If b and e are iterators over a std::vector, I can simply use if (*b == v) .... Let's assume, however, that b and e are iterators over a std::map. In this case, I should only compare the keys, not the whole value type of what's contained in the map.
So the question is, given those iterators into the map, how do I retrieve that map's comparison function that will only compare the keys? At the same time, I don't want to blindly assume that I'm working with a map either. For example, if the iterators pointed to a set, I'd want to use the comparison function defined for that set. If they pointed to a vector or deque, I'd probably have to use ==, because those containers won't have a comparison function defined.
Oh, almost forgot: I realize that in many cases, a container will only have an equivalent of operator< rather than operator== for the elements it contains -- I'm perfectly fine with being able to use that.
Iterators don't have to be connected to containers, so they don't give you any details about the containers that they aren't necessarily connected to. That's the essential iterator abstraction: iterators delimit sequences, without regard to where the sequence comes from. If you need to know about containers you have to write algorithms that take containers.
There is no standard way to map from an iterator to the underlying container type (if there is such a container at all). You might be able to use some heuristics to try to determine which container, although that will not be simple and probably not guaranteed either.
For example, you can use a metafunction to determine whether the *value_type* is std::pair<const K, T>, which is a hint that this could be a std::map and after extracting the types K and T try to use a metafunction to determine whether the type of the iterator and the type of std::map<K,T,X,Y>::iterator or std::map<K,T,X,Y>::const_iterator match for a particular combination of X, Y.
In the case of the map that could be sufficient to determine (i.e. guess with a high chance of success) that the iterator refers to a std::map, but you should note that even if you can use that and even extract the type X of the comparator, that is not sufficient to replicate the comparator in the general case. While uncommon (and not recommended) comparators can have state, and you would not know which is the particular state of the comparator without having access to the container directly. Also note that there are cases where this type of heuristic will not even help, in some implementations of std::vector<> the iterator type is directly a pointer, and in that case you cannot differentiate between an 'iterator' into an array and an iterator into a std::vector<> of the same underlying types.
Unfortunately iterators don't always know about the container that contains them (and sometimes they aren't in a standard container at all). Even the iterator_traits only have information about the value_type which doesn't specifically tell you how to compare.
Instead, let's draw inspiration from the standard library. All the associative containers (map, etc) have their own find methods rather than using std::find. And if you do need to use std::find on a such a container, you don't: you use find_if.
It sounds like your solution is that for associative containers you need a do_something_if that accepts a predicate telling it how to compare the entries.
I have a map<std::string, myStruct> I wonder how to sort items in map by int property that is in myStruct.order and if 2 or more of myStruct orders are same throw list of keys (strings) that make map unsortable by that field of myStruct? Is there any fancy way of doing in in C++03 (may be with boost)?
boost has a complete (and complex) functionality in MultiIndex, but if I understand your requirements, it's overkill in this case. A fairly easy way could be to build a list of pointers to myStruct and sort. Then you can easily check for duplicate keys (these became adjacents).
sort should use a functor of type less<const myStruct*>, i.e.
bool compare_orders(const myStruct* a, const myStruct* b) { return a->order < b->order; }
What meaning is there in "sorting" a map? Sure, the map may be internally organized as a BST or something to make access faster, but conceptionally the elements of the map are in no particular order.
Other than that, you CAN supply an ordering method for the keys (because even if you do organize the map in a particular way, it is by the order of the keys, not by that of the values), but not for the values with the third template argument for map.
You can't do this, using std::map - the first in the pair is used for comparing (it's called key). In your case, thestd::string is the key.
You can use std::set< std::pair< std::string, MyStruct > > and then implement operator< for two std::pair< std::string, MyStruct >-s.
Or, you can change the std::map's definition, if it's possible/allowed/suitable/etc. It really depends on what you're trying to do and what you're allowed to do.
Or some other container (that keeps the order of elements, as inserted - like std::list, std::vector, etc.), and then using std::sort or container's sort method, if exists.
I agree with the other answers that it's not clear why you need to sort the map. But you can use a bidirectional map to let you view both myStruct and string as keys.
There's one in boost:
http://www.boost.org/doc/libs/1_48_0/libs/bimap/doc/html/index.html
There's an example here
http://www.boost.org/doc/libs/1_48_0/libs/bimap/doc/html/boost_bimap/examples/simple_bimap.html
What is the best way to map two values to one key?
ie An item with a value and bool.
Tried using:
std::map<std::string, std::pair<std::string, bool> > myMap2
But that doesn't seem like the correct solution. Is there a more elegant way to do this?
That is indeed the correct solution. More generally, consider using std::tuple instead of std::pair for a uniform interface regardless of the number of values (as std::pair is obviously restricted to two), or boost::tuple if your compiler is too old to ship with a std:: or std::tr1:: implementation.
Either use std::pair<> as you did, or make a custom struct containing the values you want to store. I'd do the latter in most cases, as the values then have names more descriptive than first and second.
Normally, I crate a simple mapValue struct/class.
I'm looking for a C++ associative map container type which I can perform multiple key lookups on. The map needs to have constant time lookups, but I don't care if it's ordered or unordered. It just needs to be fast.
For example, I want to store a bunch of std::vector objects in a map with an int and a void* as the lookup keys. Both the int and the void* must match for my vector to be retrieved.
Does such a container exist already? Or am I going to have to roll my own? If so, how could I implement it? I've been trying to store a boost::unordered_map inside another boost::unordered_map, but I have not had any success with this method, yet. Maybe I will continue Pershing this method if there is no simpler way.
Constant look up requires a hash map. You can use a the boost::unordered_map (or tr1). The key would be the combined hash of the int and the void pointer.
If you don't want to use boost, you can try map< int, map<void*, vector> >. The lookups are however O(log(map size)).
Since C++11 you can also use an std::unordered_map, as it seems to fit your requirements quite nicely:
Unordered map is an associative container that contains key-value pairs with unique keys. Search, insertion, and removal of elements have average constant-time complexity.
In order to combine your int and void* into a single key, you can make use of std::pair.
To make the unordered map work with the pair, you have to specify a suitable hash function. In order to keep the following example short, I use a handcrafted combination of std::hash<> function calls inside a lambda expression. In case this function causes performance problems, you might want to create a more sophisticated hash.
You didn't specify the content of your vectors, so I chose int for the sake of simplicity. However, you can adapt the solution to any vector content. All in all your code could look as follows:
using Key = std::pair<int, void*>;
auto hash = [](const Key & k) {
return std::hash<int>()(k.first) * 31 + std::hash<void*>()(k.second);
};
std::unordered_map<Key, std::vector<int>, decltype(hash)> um(8, hash);
Code on Ideone
You could use boost::multi_index.
(although I think what you actually want is to use a type that contains both the void* and the integer as the key to your map, and just to compare the raw data for both in order to provide the comparison operator for the map)