Related
Is there a way to modify the key of a std::map or ? This example shows how to do so with rebalancing the tree. But what if I provide some guarantees that the key won't need to be rebalanced?
#include <vector>
#include <iostream>
#include <map>
class Keymap
{
private:
int key; // this key will be used for the indexing
int total;
public:
Keymap(int key): key(key), total(0)
{}
bool operator<(const Keymap& rhs) const{
return key < rhs.key;
}
void inc()
{
total++;
}
};
std::map<Keymap, int> my_index;
int main (){
std::map<Keymap, int> my_index;
Keymap k(2);
my_index.insert(std::make_pair(k, 0));
auto it = my_index.begin();
it->first.inc(); // this won't rebalance the tree from my understanding
return 0;
}
The modification won't compile because of the constness of it->first
Is there any way to override this behavior?
You could make inc const and total mutable
class Keymap
{
private:
int key; // this key will be used for the indexing
mutable int total;
public:
Keymap(int key): key(key), total(0)
{}
bool operator<(const Keymap& rhs) const{
return key < rhs.key;
}
void inc() const
{
total++;
}
};
But you do need to ask yourself why you are doing this, mutable isn't used much.
You're right that no rebalancing is going to happen.
If you cannot change the design and introduce surrogate read-only keys, your best option is to use Boost.MultiIndex container (I am not aware of reasonable alternatives). It is designed specifically for this purpose and has consistent built-in support of updating the indexed object, including the transactional variant. Documentation and code examples are here.
Generally, patterns like storing business entities in a self-keyed sets, having mutable keys serving additional purpose (counters and whatnot), etc. tend to have impact on maintenability, performance, and scalability of the code.
You could wrap your keys into a class that allows modification of const objects. One such class would be std::unique_ptr:
using KeymapPtr = std::unique_ptr<Keymap>;
struct PtrComp
{
template<class T>
bool operator()(const std::unique_ptr<T>& lhs, const std::unique_ptr<T>& rhs) const
{
return *lhs < *rhs;
}
};
template<class V>
using PtrMap = std::map<KeymapPtr, V, PtrComp>;
int main (){
PtrMap<int> my_index;
KeymapPtr k = std::make_unique<Keymap>(2);
my_index.emplace(std::move(k), 0);
auto it = my_index.begin();
it->first->inc(); // this won't rebalance the tree from my understanding
return 0;
}
Demo
Note that we have to supply a custom comparator object since we (presumably) want to sort by the key values, not the pointer values.
To be clear, this is not what unique_ptr is meant for, and the const semantics of smart pointers (which follow those of regular pointers) are a bit backwards from this perspective (why can I get a non-const reference from a const object? A linter may complain about this kind of use...), but it does the trick here. The same would of course work with naked pointers (where a T* const can have the T value changed but not the pointer location, whereas a const T* can have its location changed but not the T), but this mimics the ownership/lifetime model of your original code.
Needless to say, this opens the door to breaking the map invariants (breaking the sortedness by keys) so think twice before using it. But unlike const_casting your key directly, it is free of UB.
std::map and the other standard associative containers do not provide a way to do this without removing and adding an element, likely causing tree rebalancing side effects. You can go around the map key constness in various ways (e.g. using mutable members), but then it's entirely up to you to make sure you don't actually break the key ordering.
If you need this sort of efficiency but a bit more safety, you might consider changing the container to a boost::multi_index_container instead.
A std::map<K,V> is similar to:
namespace BMI = boost::multi_index;
using map_value_type = std::pair<K, V>;
using map_type = BMI::multi_index_container<
map_value_type,
BMI::indexed_by<BMI::ordered_unique<
BMI::member<map_value_type, &map_value_type::first>
>>>;
except that in a multi_index_container, the entire element is always const. If you want to be able to directly modify the second members, a means for that is described on this boost page.
multi_index_container provides two members the standard associative containers do not, replace and modify. Both of these will check for whether the modified element is in the same sort order or not. If it is, no rebalancing is done.
auto it = my_index.begin();
auto pair = *it;
pair.first.inc();
my_index.replace(it, pair);
// OR
auto it = my_index.begin();
my_index.modify(it, [](auto& pair) { pair.first.inc(); });
I am using an unordered_map of unordered_maps, such that I can reference an element using the "multi key" syntax:
my_map[k1][k2].
Is there a convenient way to use the same "multi-key" syntax to check whether an element exists before trying to access it? If not, what is the simplest way?
If your intention is to test for the existence of the key, I would not use
my_map[k1][k2]
because operator[] will default construct a new value for that key if it does not already exist.
Rather I would prefer to use std::unordered_map::find. So if you are certain the first key exists, but not the second you could do
if (my_map[k1].find(k2) != my_map[k1].end())
{
// k2 exists in unordered_map for key k1
}
If you would like to make a function that checks for the existence of both keys, then you could write something like
//------------------------------------------------------------------------------
/// \brief Determines a nested map contains two keys (the outer containing the inner)
/// \param[in] data Outer-most map
/// \param[in] a Key used to find the inner map
/// \param[in] b Key used to find the value within the inner map
/// \return True if both keys exist, false otherwise
//------------------------------------------------------------------------------
template <class key_t, class value_t>
bool nested_key_exists(std::unordered_map<key_t, std::unordered_map<key_t, value_t>> const& data, key_t const a, key_t const b)
{
auto itInner = data.find(a);
if (itInner != data.end())
{
return itInner->second.find(b) != itInner->second.end();
}
return false;
}
template<class M>
bool contains(M const&){return true;}
template<class M, class K, class...Ks>
bool contains(M const&m, K const&k, Ks const&...ks){
auto it=m.find(k);
if (it==m.end()) return false;
return contains(it->second, ks...);
}
will work for every single-valued associative container.
contains(my_map, k1, k2) is true if there is an element k1 which contains k2.
In C++20, you can use the contains method (added to all associative containers if I am not mistaken):
if (my_map.contains(k1) && my_map[k1].contains(k2))
{
// do something with my_map[k1][k2]
}
You might also use count (http://www.cplusplus.com/reference/unordered_map/unordered_map/count/ )
which will return 0 if key not exist
Something like this? (for the mutable case)
using inner_map = std::map<key_type, value_type>;
using outer_map = std::map<key_type, inner_map>
boost::optional<value_type&>
element_for_keys(outer_map& map, const key_type& k1, const key_type& k2)
{
auto it_outer = map.find(k1);
if (it_outer = map.end())
return {};
auto &map2 = it_outer->second;
auto it_inner = map2.find(k2);
if (it_inner == map2.end())
return {};
return { it_inner->second };
}
called like so:
auto op_value = element_for_keys(my_map, kv1, kv2);
if (op_value) {
// use op_value.value()
}
else {
// handle case where it does not exist
}
... or there's the more python-like way...
try {
auto& v = my_map.at(k1).at(k2);
// use v
}
catch(const std::out_of_range & e) {
// didn't find it
}
I don't believe there is a multi-key syntax to check, but the simplest way would be to use the find method. You could write a simple function to apply it to a unordered_map of unordered_maps
reference
An alternative approach is to use std::pair as key to transforming the two-level hashtable into one level hashtable, the benefit:
Simpler code and structure
Maybe faster than two-level hash table(We call fewer hash functions, get more compacted memory layout to be more cache-friendly)
The drawback: We have some key redundancy, so it would be a bad choice for large keys with many duplications, but this scenario won't be too common so the strategy here is still useful.
std::unordered_map<std::pair<int, int>, int> map;
Then to check exists:
With find and compare with end iterator
map.find(std::make_pair(k0, k1)) != map.end()
With the count function(Be aware that don't use it with unordered_multimap)
map.count(std::make_pair(k0, k1)) != 0
or C++20 contains:
map.contains(std::make_pair(k0, k1))
This question is language-agnostic, but I'm specifically looking for a solution using C++ STL containers. I have a struct like this.
struct User {
int query_count;
std::string user_id;
}
std::multiset<User> users; //currently using
I use a multiset with a comparator that sort on query_count. This allow me to have sorted multiple entries with the same query_count. Now, if I want to avoid duplicates on user_id, I need to scan data and remove the entry and create a new one, taking O(n). I'm trying to think of a way to do this in sub-linear time. I was thinking of a solution based on a map ordered on user_id, but then I would have to scan all the whole data when trying to locate the largest query_count.
EDIT: requirements are insert, delete, update(delete/insert), get highest query_count, find user_id in sub-linear time.
I prefer to use the standard stl containers, but simple modifications are fine. Is there any way to achieve my requirements?
Summary:
The summary of the answers is that to use a ootb solution, I can use boost bi-directional map.
If I'm sticking to STL, then it has to be a combination of using two maps together, updating both carefully, for each insertion of a user.
This sounds like a job for boost's multi_index: http://www.boost.org/doc/libs/1_57_0/libs/multi_index/doc/tutorial/
You can set one index based on the user id to easily prevent duplicates (you insert based on this), and then another sorted index on the query count to easily locate the max.
multi_index from boost is the way to go.
But if you want to use your own DataStructure using basic STL containers, then i suggest you create a class which has two conatiners internally.
keep an itertor to SortedContainer in the map. So that you can delete and access it in O(1)( same as lookup of unordered_map).
X
struct User {
int query_count;
std::string user_id;
}
class UserQueryCountSomething
{
typedef std::list<int> SortedContainer; //better to use a Stack or Heap here instead of list.
SortedContainer sortedQueryCount; //keep the query_count sorted here.
typedef std::pair< User, typename SortedContainer::iterator> UserPosition_T;//a pair of User struct and the iterator in list.
typedef unordered_map < std::string, UserPosition_T > Map_T; // Keep your User struct and the iterator here in this map, aginst the user_id.
Map_T map_;
public:
Insert(User u)
{
//insert into map_ and also in sortedQueryCount
}
int getHighestQueryCount()
{
//return first element in sortedQueryCount.
}
Delete()
{
//find in map and delete.
//get the iterator from the map's value type here.
//delete from the sortedQueryCount using the iteartor.
}
};
}
This can be a starting point for you. Let me know if you more details.
If we just need the highest count, not other ranks of count, then one approach may be to track it explicitly. We may do that as
unordered_map<UserId, QueryCount>;
int max_query_count;
Unfortunately, in some operations, e.g. when the user with max query count is removed, the max value need to freshly computed. Note that, for all other users, whose query count is not maximum, removal of them does not need re-computation of max_query_count. The re-computation, when done, would be O(N), which does not meet the "sub linear" requirement. That may be good enough for many use cases, because the user with maximum query count may not be frequently removed.
However, if we absolutely want to avoid the O(N) re-computation, then we may introduce another container as
multimap<QueryCount, UserId>
to map a specific query count to a collection of users.
In this approach, any mutation operation e.g. add, remove, update, may need to update both the containers. That is little bit of pain, but the gain is that such updates are expected to be logarithmic, e.g. O(lg N), i.e. sub linear.
Update with some code sketch. Note I have used unordered_map and unordered_set, instead of multimap, for count-to-user mapping. Since we do not really need ordering on count, this might be fine; in case if not, unordered_map may be simply changed to map.
class UserQueryCountTracker {
public:
typedef std::string UserId;
typedef int QueryCount;
void AddUser(UserId id) {
int new_count = -1;
auto it = user_count_map_.find(id);
if (it == user_count_map_.end()) { // id does not exist
new_count = 1;
user_count_map_[id] = new_count;
count_user_map_[new_count].insert(id);
}
else { // id exists
const int old_count = it->second;
new_count = old_count + 1;
it->second = new_count;
// move 'id' from old count to new count
count_user_map_[old_count].erase(id);
count_user_map_[new_count].insert(id);
}
assert(new_count != -1);
if (new_count > max_query_count_) {
max_query_count_ = new_count;
}
}
const unordered_set<UserId>& UsersWithMaxCount() const {
return count_user_map_[max_query_count_];
}
private:
unordered_map<UserId, QueryCount> user_count_map_{};
int max_query_count_{0};
unordered_map<QueryCount, unordered_set<UserId>> count_user_map_{};
};
Use bidirectional map, where user id is key and query count is value
#include <map>
#include <utility>
#include <functional>
template
<
typename K, // key
typename V, // value
typename P = std::less<V> // predicate
>
class value_ordered_map
{
private:
std::map<K, V> key_to_value_;
std::multimap<V, K, P> value_to_key_;
public:
typedef typename std::multimap<typename V, typename K, typename P>::iterator by_value_iterator;
const V& value(const K& key) {
return key_to_value_[key];
}
std::pair<by_value_iterator, by_value_iterator> keys(const V& value) {
return value_to_key_.equal_range(value);
}
void set(const K& key, const V& value) {
by_key_iterator it = key_to_value_.find(key);
if (key_to_value_.end() != it) {
std::pair<by_value_iterator, by_value_iterator> it_pair = value_to_key_.equal_range(key_to_value_[key]);
while (it_pair.first != it_pair.second)
if (it_pair.first->first == it->second) {
value_to_key_.erase(it_pair.first);
break;
} else ++it_pair.first;
}
key_to_value_[key] = value;
value_to_key_.insert(std::make_pair(value, key));
}
};
I am working on a simple hash table in C++. I have methods to insert, delete, and search the hash table for the specified key. I know that the C++ map STL container can handle my situation, but I would kind of like to code my own as an educational exercise.
Basically I have a hash table that will take a single string and map it to a vector of other strings. This is easy to do in a method because calling a .Add() or .Delete() will behave as expected. I would however like to create an overloaded [] operator to the class that is able to do these operations on the vector.
For example, if I want to add an item to the vector I can write something like this:
hashTable[string1] = newString;
This will set the new string as a member of my vector. The same can be said for delete and search.
hashTable[string1] = "";
cout << hashTable[string1] << endl;
My major problem is that I do not know how to overload the [] operator to gain this functionality. I have this function coded up right now. It works on a basic 1 to 1 string match, but not on a string to vector match.
//Return a reference to a vector to update then reassign?
vector& HashClass::operator[](const string index)
{
assert(size >= 0 && size < maxSize);
Hash(key);
return hashTable[index];
}
I think I'm most stuck on the idea of having a vector return that later needs to be assigned. As the user, I would find this kludgy.
This question is closely related to another question: what behavior do
you want when you access a non-existant value other than in an
assignment? In other words, what do you want to happen when you write:
std::cout << hashTable[string] << std::endl;
and string is not present in the table?
There are two possible approaches: you can consider it an error, and
throw an exception, or abort, or something similar; or you can return
some sort of default, built with the default constructor, or provided by
the client earlier.
The standard map and unordered_map take the second approach, using the
default constructor to construct a new value. This allows a very simple
solution: if operator[] isn't present, you insert it, initializing it
with the default value. Then you return a reference to it;
hashTable[string] = newString; assigns through the reference to an
already existing value.
In many use cases, the first approach will be preferable (perhaps with a
contains function, so you can test up front whether the operator[]
will find something or not). To implement the first approach, you must
first implement specific functions for each type of access:
template <typename Key, typename Value>
class HashTable
{
public:
Value* get( Key const& key ) const;
void set( Key const& key, Value const& value );
};
(I generally make these public; there's no reason to forbid their use by
a client.)
Then, you define operator[] to return a proxy, as follows:
template <typename Key, typename Value>
class HashTable
{
public:
class Proxy
{
HashTable* myOwner;
Key myKey;
public:
Proxy( HashTable* owner, Key const& key )
: myOwner( owner )
, myKey( key )
{
}
operator Value const&() const
{
Value const* result = myOwner->get( myKey );
if ( result == NULL ) {
// Desired error behavior here...
}
return *result;
}
Proxy const& operator==( Value const& value ) const
{
myOwner->set( myKey, value );
return *this;
}
};
Value* get( Key const& key ) const;
void set( Key const& key, Value const& value );
Proxy operator[]( Key const& key )
{
return Proxy( this, key );
}
};
Thus, when you write:
hashTable[key] = newString;
, the proxy's operator= will call hashTable.put( key, newString );
in other contexts, however, it will call the implicit type conversion on
the proxy, which calls hashTable.get( key ).
In some cases, even if you desire to return a default value, it may be
preferable to use this solution: the get function is not required to
insert anything into the hash table, so the table doesn't fill up with
all of the misses, and you can overload the operator[] on const, so
you can use it on a const hash table as well. Also, it doesn't
require the value type to have a default constructor.
It does have one disadvantage with respect to the solution used in the
standard; since you can't overload operator., you can't make the proxy
behave like a reference, and things like:
hashTable[string].someFunction();
don't work. A work-around is to overload operator-> in the proxy, but
this leads to a somewhat unnatural syntax:
hashTable[string]->someFunction(); // But the hash table contains
// values, not pointers!!!
(Don't be mislead by the implicit conversion to a reference. An
implicit conversion will not be considered for a in an expression
a.b.)
In C++, [] access to associative containers is generally given the semantics of default-constructing an object of the mapped type, inserting it with the key, and returning a reference to the inserted mapped object.
So your operator[] would be implemented as:
string& HashClass::operator[](const string index)
{
assert(size >= 0 && size < maxSize);
Hash(key);
vector &v = hashTable[index];
if (index in v) {
...
} else {
v.push_back(string());
return v.back();
}
}
string var;
void setvar(string ivar)
{
var=ivar;
}
string getVar() const
{
return var;
}
as same way how can i write setter and getter method for a map like this
std::map varmap;
You can write a getter or setter for a field that's a std::map just as you would any other field - just have the getter return a std::map and have the setter accept a std::map.
Of course, if you have a field that's a std::map that you're trying to use getters and setters on, that might suggest that there's a better way to structure the program. Can you provide more details about what you're trying to do?
EDIT: The above answer is for a slightly different question than the one you asked. It seems like what you're interested in is
Given a class with a std::map as a data member, write a function to set a given key/value pair and a function to return the value associated with a given key.
The setter logic for this is not too hard - you just write a function that takes in the key and value and associates the key with the value. For example:
void put(const string& key, const string& value) {
varmap[key] = value;
}
Writing a getter is trickier because there's no guarantee that there's a value associated with a particular key. When this happens, you have multiple options.
You could return a sentinel value. For example, you might return an empty string if the given value isn't stored in the map anywhere. This makes the code for using the function easier to read, but risks using an invalid value in code.
You could throw an exception. This would be good if it represents a serious error for the given value not to exist. This has the drawback that if you look up a value, you always need to try/catch the logic to avoid propagation of errors.
You could associate a default value with the key, then hand that back. If you're writing a program that represents a music library, for example, you might hand back "(none)" or "(unknown)" if you tried to look up the artist for a song on which you have no data, for example.
No one of these approaches works best, and you'll need to think over which is most appropriate to your particular circumstance.
Entries in a std::map<Key, Value> must have a key and a value. The normal way of getting and setting them is:
my_map[a_key] = new_value; // set
do_something_with(my_map[a_key]); // get and use...
If you want to add new functions, they probably wouldn't look like what you're proposing because:
your set is only given one parameter despite needing a key and value (admittedly, you could adopt some convention like having the first ':' or '=' separate them), and
the get() function doesn't provide any key.
You could instead have something more like:
void set(const Key&, const Value&);
std::string get(const Key&) const;
But, even if you have write permissions to do so, you shouldn't add that directly in the map header file - all C++ programs compiled on that computer will share that file and won't expect it to be modified. Any small mistake could cause trouble, and if you ship your program to another computer you won't be able to compile it there without making a similar modification - if that computer uses a different C++ compiler the necessary details of that modification may be slightly different too.
So, you can either write your own (preferably templated) class that derives from (inherits) or contains (composition) a std::map, providing your functions in your custom class. An inheritance based solution is easier and more concise to write:
template <typename Key, typename Value>
struct My_Map : std::map<Key, Value>
{
My_Map(...); // have to provide any non-default constructors you want...
void set(const Key& key, const Value& value) { operator[](key) = value; }
// if you want entries for non-existent keys to be created with a default Value...
Value& get(const Key& key) { return operator[](key); }
--- OR ---
// if you want an exception thrown for non-existent keys...
Value& get(const Key& key) { return at(key); }
const Value& get(const Key& key) const { return at(key); }
};
This is slightly dangerous if you're planning to pass My_Maps around by pointer and accidentally end up with a "new My_Map" pointer that's later deleted as a std::map pointer, as in:
void f(std::map<int, string>* p) { /* use *p */ delete p; }
My_Map<int, string>* p = new My_Map<int, string>;
f(p);
Still, in most programs there's no real danger of accidentally disposing of a map like this, so go ahead and do it.
Further, and this is the kind of thinking that'll make me unpopular with the Standard-fearing purists around here - because My_Map hasn't added any data members or other bases, the std::map<> destructor probably does all the necessary tear-down even though it's technically Undefined Behaviour. I'm NOT encouraging you to ignore the issue (and would consider it unprofessional in a job requiring robustness), but you can at least rest a little easier. I'd be curious to hear from anyone with any compiler/settings where it demonstrably doesn't operate safely.
If you use composition, you'll have to write your own "forwarding" functions to let you use My_Map like a std::map, accessing iterators, find, erase, insert etc.. It's a pain.
Setter and getter for std::map is no different except that you need to pass the necessary parameters for the setter. Assume if I have a struct and has a member variable whose type is std::map, whose key is of type char and data is of type int. Method signatures would be of the format -
void setEncode( char* key, int* data, const int& size ); Because, std::map requires a key, data and sizes of these arrays being passed. With out knowing size, it is unknown as how far to insert the elements in to the container.
std::map<char, int> getEncode() const ; const key word signifies it a non-modifying member function. Because it's functionality is to just return a variable of type std::map.
Example -
struct myMap
{
std::map<char, int> encode;
void setEncode( char* key, int* data, const int& size );
std::map<char, int> getEncode() const ;
};
void myMap::setEncode( char *key, int* data, const int& size )
{
int i=0;
while( i < size )
{
encode.insert(std::pair<char, int>(key[i], data[i]));
++i ;
}
}
std::map<char, int> myMap::getEncode() const
{
return encode;
}
Results IdeOne. This should give you an idea, but should also follow the general rules what #templatetypedef, #tony suggested.
Do you want to set a key value pair in an existing map(probably that's what you want) or create a new map itself?
void setvar(string key, int value)
{
myMap[key] = value;
}
int getVar(string key) const
{
return myMap[key];
}
where int and string are interchangeable
For latter you'll probably have to interate over all map values for setting and getter should be just to return that map pointer.