i want to access a QMap by it's value, but i don't want to iterate over it and find element with same value and use it's key,
is there anyway to find QMap key by it's content?
my code is :
QMap<int, QVector<QString> >::iterator it;
QMap <QString, int> m_all_data;
i want to access to element of m_all_data with value of my iterator key;
You can use:
const Key QMap::key ( const T & value ) const
which returns the first key with value value or
QList<Key> QMap::keys ( const T & value ) const
which returns a list containing all the keys in the map in ascending order.
But it is slow (linear time), because QMap's internal data structure is optimized for fast lookup by key, not by value.
You can use QMap::values (http://qt-project.org/doc/qt-4.8/qmap.html#values) to get the values.
This will give you a QList on which you can iterate through, and for the given value you can get the key using QMap::key (http://qt-project.org/doc/qt-4.8/qmap.html#key) to get the key for the given value.
You could maintain a second QMap with iterators pointing into the first map, i.e.
QMap<QString, int> m_all_data;
QMap<int, QList<QMap<QString, int>::iterator> > m_data_by_int;
Note that each int value would map to list of iterators since there may be multiple map entries with the same value. Using iterators avoids that you duplicate the QString data. You'd have to make sure to keep the two maps syncronized though, so it might be best to wrap the two maps into a 'bidirectional map' class.
Related
I am trying to implement a dictionary where i have an outer map (as a multimap) with the key being the word being searched and the value being the inner map, which will have several pairs itself with different values which all can map to the outer multimap key.
for example: the word Distinct has several meanings depending if its a noun, verb, adjective, or pronoun ==> noun- A keyword in this program
adverb- Uniquely. Written "distinctly" etc.
I am thinking of mapping the word Distinct as the key to the outer multimap and mapping the part of speech as the key to the inner map with the definitions as the inner map's values.
so far i declared the multimap as this:
typedef map<string, string> valMap;
multimap<string,valMap> myMultMap;
and i have tried adding values by using insert() like this:
myMultMap.insert("Diction", valMap.insert(pair<string,string>("fun", "first Value"));
I am just learning maps and still unsure as to the inner working of iterators in the maps. Any help would be greatly appreciated.
First, create the inner map and store it into a variable. Then use insert to add it into the outer map.
So first create the variable you need to insert:
valMap tmp;
tmp.insert(make_pair("fun", "first Value"));
Then insert this tmp into the main map:
myMultMap.insert(make_pair("Diction", move(tmp)));
multimap::insert returns an iterator to the stored entry. You can use this iterator to insert items into inserted map without creating any temporary variables. It is also a good idea to use emplace forwarding arguments directly to entry constructor instead of insert to avoid creation of temporaries:
using t_Map = ::std::map<::std::string, ::std::string>;
using t_Multimap = ::std::multimap<::std::string, t_Map>;
t_Multimap multimap{};
auto const p_entry
{
multimap.emplace
(
::std::piecewise_construct
, ::std::forward_as_tuple("Diction")
, ::std::forward_as_tuple()
)
};
auto & map{p_entry->second};
map.emplace
(
::std::piecewise_construct
, ::std::forward_as_tuple("fun")
, ::std::forward_as_tuple("first Value")
);
So i'm fairly new to c++ and i'm a little confused on how to implement the find() function on my set which is storing a pair item. Ive read on how to insert and remove items by their pair but came up dry on anyone explaining how to use find (Or some other method, if there is one) to find a value by the first item of the pair.
set<pair<string, CustomObject>> *items = new set<pair<string, CustomObject>>();
Then lets say I insert a few pairs into the set then I want to find one of those pair by searching for the "key" being stored as the first item in the pair. I think it would involve calling the .first on the pair but im just having trouble with that. This is the basic function im trying to implement
bool inSet(string key){
return this->items->find(pair<string, CustomObject>(key, null).first)
}
I was able to implement everything just fine in a map object but then I had to switch to a set because I wanted to be able to sort the items in the data structure and I was told that you cant efficiently do this in a map, hence the set.
std::set stores and searches for values based on the entire value. So when you do a find for pair(key, null), and the set contains pair(key, somevalue), it won't find it, as they are not the same.
If you want to search by just the key, you need a std::map. As you say, that doesn't do any searching or sorting by the value, so you can only have one entry with a given key.
If you want to search/sort by both just the key and the key,value pair (different searches at different points in the lifetime of the same data structure), then you'll need a more complex arrangement.
a map of sets can do what you want:
std::map<string, std::set<CustomObject>> items;
Now when you just want to look up things by key, you just lookup in the map, getting back a set of all the values with that key. If you want to search further for a specific value, you look it up in that set.
To find key in std::set by key stored in pair you need to redefine order comparision procedure for your set (if you need multiple objects use multiset):
typedef pair<string, CustomObject> SetValue
struct CustomObjectCompare {
bool operator() (const SetValue& lhs, const SetValue& rhs) const{
return rhs.first < rhs.first;
}
};
// use multiset insead of set if you need multiple objects per one key
typedef set<pair<string, CustomObject>, CustomObjectCompare> Set;
Set mySet;
bool inSet(string key){
static CustomObject emptyObject;
return mySet.end() != mySet.find(SetValue(key, emptyObject))
}
This example define comparision object CustomObjectCompare and special set class Set with that comparision object. As search as sorting will be only by string. The function isSet search by string and emptyObject is ignored and may be any of existed object. In example it is an function internal once initialized static object.
I'm looking for a two-dimensional hash map where the row and column indexes are pointers. I.e., instead of unsigned, consecutive integers being the row and column indexes, I require them to be pointers.
I do not care about insertion performance or its size in memory, but I do need fast lookup and iteration.
A basic interface could look like:
template<typename Key, typename Value>
class pointer_matrix
{
public:
iterator insert(Key const& row, Key const& column, Value& value);
Value& at(Key const& row, Key const& column);
row_iterator row(Key const& row);
column_iterator column(Key const& column);
};
This interface would allow me two types of lookups:
Given two keys, I can identify the corresponding value object: (Key, Key) => Value
Given just one key, I can iterate over a number of value objects; this vector of value objects represents either the row or the column, depending on the lookup: Key => (Value, Value, ...)
It is basically a "table" where both the column and the row headers are pointers, instead of consecutive integers starting at 0.
Searching Google for "pointer matrix" or "hash matrix" turns up information about simple my_type** matrixes, which is definitely not what I need.
Does a container like that exist? If not: What would be the tools sensible to build such a container?
What you describe is a hash table of hash tables. That is, every bucket is a small hash table with (conceptually) a different hash function. A different size may serve as a different hash function if you do % size.
I guess you're trying to achieve some sort of perfect hashing, and this is one of the ways there. You can read about it in wikipedia.
If your interest is in the real-world (as opposed to academic) I'd test this against normal hashing, with linked list buckets.
The lookup performance of perfect hashes is not guaranteed to be any better.
Use a multimap (MM) >.
When you add a value , you must also insert > and >.
When inserting, , you must search for key1, if found you insert in the map insert returned as a value (MM_iter->second).
Otherwise you create a map with and insert it in MM.
This way, if you search a unique key, return all the values in the map returned by MM.find(key);
if you make a search using 2 keys, MM.find(key1).find(key2).
In a C++ std::map, is there any way to search for the key given the mapped value? Example:
I have this map:
map<int,string> myMap;
myMap[0] = "foo";
Is there any way that I can find the corresponding int, given the value "foo"?
cout << myMap.some_function("foo") <<endl;
Output: 0
std::map doesn't provide a (fast) way to find the key of a given value.
What you want is often called a "bijective map", or short "bimap". Boost has such a data structure. This is typically implemented by using two index trees "glued" together (where std::map has only one for the keys). Boost also provides the more general multi index with similar use cases.
If you don't want to use Boost, if storage is not a big problem, and if you can affort the extra code effort, you can simply use two maps and glue them together manually:
std::map<int, string> myMapForward;
std::map<string, int> myMapBackward; // maybe even std::set
// insertion becomes:
myMapForward.insert(std::make_pair(0, "foo"));
myMapBackward.insert(std::make_pair("foo", 0));
// forward lookup becomes:
myMapForwar[0];
// backward lookup becomes:
myMapBackward["foo"];
Of course you can wrap those two maps in a class and provide some useful interface, but this might be a bit overkill, and using two maps with the same content is not an optional solution anyways. As commented below, exception safety is also a problem of this solution. But in many applications it's already enough to simply add another reverse map.
Please note that since std::map stores unique keys, this approach will support backward lookup only for unique values, as collisions in the value space of the forward map correspond to collisions in the key space of the backward map.
No, not directly.
One option is to examine each value in the map until you find what you are looking for. This, obviously, will be O(n).
In order to do this you could just write a for() loop, or you could use std::find_if(). In order to use find_if(), you'll need to create a predicate. In C++11, this might be a lambda:
typedef std::map <unsigned, Student> MyMap;
MyMap myMap;
// ...
const string targetName = "Jones";
find_if (myMap.begin(), myMap.end(), [&targetName] (const MyMap::value_type& test)
{
if (test.second.mName == targetName)
return true;
});
If you're using C++03, then this could be a functor:
struct MatchName
: public std::unary_function <bool, MyMap::value_type>
{
MatchName (const std::string& target) : mTarget (target) {}
bool operator() (const MyMap::value_type& test) const
{
if (test.second.mName == mTarget)
return true;
return false;
}
private:
const std::string mTarget;
};
// ...
find_if (myMap.begin(), myMap.end(), MatchName (target));
Another option is to build an index. The index would likely be another map, where the key is whatever values you want to find and the value is some kind of index back to the main map.
Suppose your main map contains Student objects which consist of a name and some other stuff, and the key in this map is the Student ID, an integer. If you want to find the student with a particular last name, you could build an indexing map where the key is a last name (probably want to use multimap here), and the value is the student ID. You can then index back in to the main map to get the remainder of the Student's attributes.
There are challenges with the second approach. You must keep the main map and the index (or indicies) synchronized when you add or remove elements. You must make sure the index you choose as the value in the index is not something that may change, like a pointer. If you are multithreading, then you have to give a think to how both the map and index will be protected without introducing deadlocks or race conditions.
The only way to accomplish this that I can think of is to iterate through it. This is most likely not what you want, but it's the best shot I can think of. Good luck!
No, You can not do this. You simply have to iterate over map and match each value with the item to be matched and return the corresponding key and it will cost you high time complexity equal to O(n).
You can achieve this by iterating which will take O(n) time. Or you can store the reverse map which will take O(n) space.
By iterating:
std::map<int, string> fmap;
for (std::map<int,string>::iterator it=fmap.begin(); it!=fmap.end(); ++it)
if (strcmp(it->second,"foo"))
break;
By storing reverse map:
std::map<int, string> fmap;
std::map<string, int> bmap;
fmap.insert(std::make_pair(0, "foo"));
bmap.insert(std::make_pair("foo", 0));
fmap[0]; // original map lookup
bmap["foo"]; //reverse map lookup
At the moment my solution is to iterate through the map to solve this.
I see there is a upper_bound method which can make this loop faster, but is there a quicker or more succinct way?
The end:
m.rbegin();
Maps (and sets) are sorted, so the first element is the smallest, and the last element is the largest. By default maps use std::less, but you can switch the comparer and this would of course change the position of the largest element. (For example, using std::greater would place it at begin().
Keep in mind rbegin returns an iterator. To get the actual key, use m.rbegin()->first. You might wrap it up into a function for clarity, though I'm not sure if it's worth it:
template <typename T>
inline const typename T::key_type& last_key(const T& pMap)
{
return pMap.rbegin()->first;
}
typedef std::map</* types */> map_type;
map_type myMap;
// populate
map_type::key_type k = last_key(myMap);
The entries in a std::map are sorted, so for a std::map m (assuming m.empty() is false), you can get the biggest key easily: (--m.end())->first
As std::map is assosiative array one can easily find biggest or smallest key very easily. By defualt compare function is less(<) operator so biggest key will be last element in map. Similarly if someone has different requirement anyone can modify compare function while declaring map.
std::map< key, Value, compare< key,Value > >
By default compare=std::less
Since you're not using unordered_map, your keys should be in order. Depending upon what you want to do with an iterator, you have two options:
If you want a forwards-iterator then you can use std::prev(myMap.end()). Note that --myMap.end() isn't guaranteed to work in all scenarios, so I'd usually avoid it.
If you want to iterate in reverse then use myMap.rbegin()
Since the map is just an AVL tree then, it's sorted -in an ascending order-. So, the element with largest key is the last element and you can obtain it using one of the following two methods:
1.
largestElement = (myMap.rbegin())-> first; // rbegin(): returns an iterator pointing to the last element
largestElement = (--myMap.end())->first; // end(): returns an iterator pointing to the theortical element following the last element