Get all the keys which matches a query in a map - c++

Say I have more than one key with the same value in a map. Then in that case how do I retrieve all keys that matches a query.
Or, Is there any possibility to tell find operation to search after a specific value.
I am using an std::map, C++.

Would something like this work for you:
void FindKeysWithValue(Value aValue, list<Key>& aList)
{
aList.clear();
for_each(iMap.begin(), iMap.end(), [&] (const pair<Key, Value>& aPair)
{
if (aPair.second == aValue)
{
aList.push_back(aPair.first);
}
});
}

The associative containers probably won't help you too much because for std::map<K, V> the key happens to be unique and chances that your chosen query matches the ordering relation you used may not be too high. If the order matches, you can use the std::map<K, V> members lower_bound() and upper_bound(). For std::multimap<K, V> you can also use equal_range().
In general, i.e., if you query isn't really related to the order, you can use std::copy_if() to get a sequence of objects matching a predicate:
Other other;
// ...
std::vector<Other::value_type> matches;
std::copy_if(other.begin(), other.end(),
std::back_inserter(matches), predicate);
When copying the elements is too expensive, you should probably consider using std:find_if() instead:
for (auto it(other.begin());
other.end() != (it = std::find_if(it, other.end(), predicate));
++it) {
// do something with it
}

The only way is to iterate over map.
this link may be useful: Reverse map lookup

Provided you want quick access and you don't mind using some more space, then you maintain another map that gets stored as value, key. In your case, you would need to handle the duplicate values (that you will be storing as keys).
Not a great idea but definitely an option.

A map is meant for efficient lookup of keys. Lookup based on values is not efficient, and you basically have to iterate through the map, extracting matches yourself:
for(map<A,B>::iterator i = m.begin(); i != m.end(); i++)
if(i->second == foo)
you_found_a_match();
If you intend to do this often, you can build up a multimap mapping the other way, so you can efficiently perform a value-based lookup:
multimap<B,A> reverse;
for(map<A,B>::iterator i = m.begin(); i != m.end(); i++)
reverse.insert(pair<B,A>(i->second,i->first));
You can now easily find the keys with a given value value:
matches = reverse.equal_range(value);
for(multimap<B,A>::iterator i = matches.first; i != matches.second; i++)
A & key = i->second;
If these maps aren't going to grow continuously, it may be more efficient to simply maintain a vector > instead, define a comparator for it based on the value, and use equal_range on that instead.

Related

Iterating over a map, starting at a specific key

I am implementing a function meant to find any strings that share a prefix with a given string. All of the possible strings to compare to are in a map already, and I would like to iterate over that map starting at where the given string is. Currently, I am looping over the entire map, but for performance reasons, I need to make this more efficient. This is how I am currently iterating over the map:
for(auto const& it : lookup_map){ //performs code }
I would like this to not start from the beginning of the map, but wherever the given string is in the map.
Just use good old iterators:
for( auto it = lookup_map.find( your_string ); it != lookup_map.end(); ++it ) {
// using it
}
std::map has its own member function lower_bound for what you want to do. You can use std::map::lower_bound to get your starting position and then do a compare of the prefix for subsequent iterations:
for (auto it = lookup_map.lower_bound(prefix);
it != std::end(lookup_map) && it->first.compare(0, prefix.size(), prefix) == 0;
++it)
{
...
}
This will be more efficient than iterating every single key. The advantage in this case of using lower_bound() is that it will return the first item that is equivalent or after the search term. So if your search term is "aa" and you have an entry "aab" in your map, lower_bound() will return an iterator to "aab". I think this will be more useful in your case because you want to search on the prefix.
In C++20, std::string has a starts_with() function. So we can use this function to check the prefix and simplify our code a little:
for (auto it = lookup_map.lower_bound(prefix);
it != lookup_map.end() && it->first.starts_with(prefix); ++it)
{
...
}
Demo

How to determine whether a value exists in map in C++

I understand that std::map is (Key, Value) pairs.
I want to search through the values of a map. Let us say that I want to find the highest value among the values in the std::map. How can I do that ?
For example let me consider a map like this:
John -> 100
Jeffrey -> 200
Krishna -> 147
I think it will be similar to this , but I am not sure.
for (auto it=m.begin(); it!=m.end(); it++)
{
if (it->second == 500)
{
cout << "Found";
}
else {
continue;}
}
Instead of iterating through std::map, is there any other inbuilt method using which I can check if a value exists in a std::map with O(1) time complexity ?
Q1: How to check if a value exists in hashmap?
You need to iterate through and check if such item exists. You can use `std::find_if() with a lambda or do that through a loop. If you do that quite often you may want to index values as well (see below)
Q2: How to iterate through all the values in a map and find the largest value or the smallest value ?
Again you iterate through container and find it or you can use std::max_element() or std::min_element() with a lambda as well. Though if you need to access values in sorted order you may consider to use boost::multimap which will allow to access data using hashed index by name and provide sorted or hashed index(es) for values, though you should be aware of a price of every index added.
For the second question, use:
std::map<std::string, int> foo = {{"John",100},{"Jeffrey",200},{"Krishna",147}};
std::cout << std::max_element(foo.begin(), foo.end(), [](const auto& p1, const auto& p2){return p1.second < p2.second;})->first;
std::cout << std::min_element(foo.begin(), foo.end(), [](const auto& p1, const auto& p2){return p1.second < p2.second;})->first;
Use an adapted lambda with std::find_if, you should be able to find also if a value exists in a map (or hash table).

std::map - Element access without exception and without insertion

I have a recurrent pattern with the use of std::map.
I want to retrieve the value only when the key is present, otherwise I don't want to insert element. Currently I'm using count(key) or find(key) (which one is better? from the documentation the complexity seems to be the same) and if them returns a positive value that I access the map. However I would like to avoid the use of two operations on the map. Something like:
map<string, int> myMap;
int returnvalue;
boole result = myMap.get("key1",returnValue)
if(result){
\\ use returnValue
}
Reading the std::map documentation on cplusplus.com I found two functions for accessing map elements:
at(): which throws an excpetion if the key is not present
[]: which insert a new value if the key is not present
None of them satisfy my necessity.
Use map::find:
auto it = myMap.find(key);
if (it != myMap.end())
{
// use it->second
}
else
{
// not found
}
This part was easy. The harder problem is when you want to look up if an element exists and return it if it does, but otherwise insert a new element at that key, all without searching the map twice. For that you need to use lower_bound followed by hinted insertion.
using count() for sure the key is exists
then uses find() to get the k/v pair
if (myMap.count(key))
{
auto it = myMap.find(key)
}
else
{
// not found
}

Elegant and efficient algorithm for increasing values of a "vector<pair>"

I need to find an element in a vector<pair<int, float>> and increase the second value.
I tried an approach.
template <typename K, typename V>
struct match_first {
const K _k; match_first(const K& k) : _k(k) {}
bool operator()(const pair<K, V>& el) const {
return _k == el.first;
}
};
Eg to use.:
vector< pair<int, float> > vec;
vec.push_back(make_pair(2, 3.0));
vec.push_back(make_pair(3, 5.0));
vec.push_back(make_pair(1, 1.0));
vector< pair<int, float> >::iterator it = find_if(vec.begin(), vec.end(), match_first<int, float>(3));
if (it != vec.end()) {
it->second += 9;
}
There is a more efficient way of accomplishing this task?
A map seems more natural:
#include <map>
int main()
{
std::map<int, float> m;
m.insert(std::make_pair(2, 3.0));
m.insert(std::make_pair(3, 5.0));
m.insert(std::make_pair(1, 1.0));
auto it = m.find(3);
if (it != m.end()) {
it->second += 9;
}
}
It will also be faster because lookup is O(log(n))
You can reach the same complexity with a vector of sorted pairs by using std::lower_bound (or std::equal_range if keys can be repeated)
It depends on your constrains. If you have the unique key (the first element) you can use std::map<K,V> to hold your objects. Then increasing it is easy. If V has a default constructor initializing it to zero, you can even skip adding new elements and just increment (I am not sure it will work with ints through).
std::map<K,V> data;
data[key] = data[key] + 1;
the [] operator used for non-existent key will create the object for you using its default constructor. To just access data use at or find methods.
extending sehe's answer: You can use std::multimap in the same way if you may have duplicate keys. This container also keeps the <K,V> pair in sorted order(keys) so binary search approach obviously speed up things.
There is no exact answer to your question: it depends.
My first answer is: use std::find_if (available in <algorithm>, part of the C++ Standard Library), then profile your code. If the search turns out to be a bottleneck worthy of concern, then try another approach.
Beware of using a std::map, as it will sort the pairs by their first component (that is, the insertion order will be lost). In addition, it will not allow you to store two pairs with the same first component.
As others have mentioned, you can work around this caveats (if they are indeed caveats to your problem), but, like I mentioned before, it would only be worth your while if you demonstrate first that the search turned out to be a bottleneck after using the standard algorithms.

finding a key in a map

I have a map which I have declared as follows:
map<int, bool> index;
and I insert values into the map as:
int x; cin>>x;
index[x]=true;
However,
cout<<index[y]; // for any number y not inindexgives me 0
As I get the value 0 when I check for a key which is not present in the map, how can I reliably find out if a key is present in the map or not?
I'm using a map for trying to find out if two sets are disjoint or not, and for the same I am using a map, and two vectors to store the input. Is this shabby in any way? Some other data structure I should be using?
You can use if (index.find(key) == index.end()) to determine if a key is present. Using index[key] you default-construct a new value (in this case, you call bool(), and it gets printed as 0.) The newly constructed value also gets inserted into the map (i.e. index[key] is equal in this case to index.insert(std::make_pair(key, bool()).)
Using two data structures for the same data is ok. However, is there any need to use a map, wouldn't a set suffice in your use case? I.e. if they key is presents, the value is true, and false otherwise?
To find if two sets (given as std::set) are disjoint, you can simply compute their intersection:
std::set<T> X, Y; // populate
std::set<T> I;
std::set_difference(X.begin(), X.end(), y.begin(), y.end(), std::back_inserter(I));
const bool disjoint = I.empty();
If your containers aren't std::sets, you have to make sure the ranges are ordered.
If you want to be more efficient, you can implement the algorithm for set_intersection and stop once you have a common element:
template <typename Iter1, typename Iter2>
bool disjoint(Iter1 first1, Iter1 last1, Iter2 first2, Iter2 last2)
{
while (first1 != last1 && first2 != last2)
{
if (*first1 < *first2) ++first1;
else if (*first2 < *first1) ++first2;
else { return false; }
}
return true;
}
Use map::find.
you can use index.find(key) != index.end() or index.count(key) > 0
Depending on the range of index items, it might be good to use a bitmap (only makes sense for a reasonnably small range of possible index items. Will make checks for being disjoint super easy and efficient) or use a a set instead of a map (map stores additional bools that are not really needed). A set also offers methods count(key) and find(key)
1, Use index.count(y). It's more concise than and equivalent to index.find(y) != index.end(), except for the fact that it's an integer 1 or 0, whereas of course != gives you a bool.
The downside is that count is potentially less efficient for multimap than it is for map, since it may have to count more than one entry. Since you aren't using a multimap, no problem.
2, You could sort both vectors and use std::set_intersection, but it's not a perfect fit if all you care is whether the intersection is empty or not. Depending where the input comes from, you may be able to get rid of both vectors and just construct a map as you go from the first load of input, then check each element of the second load of input against it. Finally, use a set instead of a map.