Find element in vector of pair and output c++ - c++

I have a vector of pair:
typedef pair<string,int> is;
vector<is> v;
I push some values to the vector.
v.push_back(make_pair("One",1));
v.push_back(make_pair("Two",2));
v.push_back(make_pair("Three",3));
v.push_back(make_pair("Four",4));
I need to ask the user to input a name and search the vector , find that name and output it's corresponding int in the pair. If user types "One" I want the input to type 1.
I tried the following.
struct comp_pair_int
{
bool operator()(const pair<string, int>& a, const string& b)
{
return (a.first < b);
}
bool operator()(const string& a, const pair<string, int>& b)
{
return (a < b.first);
}
};
sort(v.begin(),v.end(),comparison);
if (binary_search(v.begin(), v.end(),
"One", comp_pair_int()))
cout << "Element found\n";
else
cout << "Element not found";
That code returns if the element is found or not, but that's not all I want, I also need to output the second element in the pair of the found element. How can I do that?

std::binary_search will only give you a bool result, so it doesn't give sufficient information to get the value of the pair you're looking for.
The idiomatic way to do this is with std::lower_bound, which returns an iterator to the pair you're looking for, like this:
if (auto i = std::lower_bound(v.begin(), v.end(),
"One", comp_pair_int());
i != v.end() && i->first == "One") // lower bound actually found correct pair
cout << "Element found with value " << i->second;
else
cout << "Element not found";
Note that as with binary_search the range needs to be sorted by the same predicate you use for the search.

You could use std::find_if if your vector is not sorted by key.
Would look like this:
auto it = std::find_if(v.begin(), v.end(), [&](const is& item) {
return item.first == user_input;
});
if(it != v.end()) {
int my_item = it->second;
}
else {
// key not found
}

Related

Add element from map to pair only if the value doesn't already exist (C++)

I am trying to add the elements from a map to a pair vector, and then sort the vector according to the value, but i dont want to add elements that have the same value, and i can't figure out how to make such an if statement.
The map contains the amount of times a word was repeated in the input in main() and the word itself, and i want to sort the vector that has the map elements, but i dont want to repeat words that have been repeated the same amount of times.
This is what i have so far:
bool compara(pair<string, unsigned int>& a,
pair<string, unsigned int>& b)
{
return a.second > b.second;
}
void sortP(map<string, unsigned int> &M, unsigned int x)
{
vector<pair<string, unsigned int> > A;
for (auto& it : M) {
if(find(A.begin(), A.end(), it.second) == A.end()) // this is the part that
A.push_back(it); // doesn't work
}
sort(A.begin(), A.end(), compara);
for (auto& it : A) {
cout << it.second << "\t"
<< it.first << endl;
}
cout << endl << endl;
// this is where i want to output the element of the vector that appears on the 'x'
// position, after it was sorted
}
I apologize if the terminology isn't exactly correct, i have just started getting accustomed to working with maps and pairs.
Since you are searching through a vector of pairs, you need to use std::find_if() instead of std::find() to find a vector element that matches a particular field of the pair, eg:
for (auto& it : M) {
if (find_if(A.begin(), A.end(), [&](pair<string, unsigned int>& p){ return p.second == it.second; }) == A.end())
A.push_back(it);
}
Alternatively, you could just use another map instead of a vector, using it.second as the key type, and letting the map handle the sorting and duplicate handling for you.

How to return an iterator from a function including the end case

In c++ I need to search a vector containing a pair, in reverse, by the string. I cannot use a map because the strings are not unique and order is important. I then want to return a forward iterator if the string is found or the end iterator if the string is not found.
Please see below for my current code. I have no problem when the string is found but, if the string is not found, I get a segfault in the conditional statement in main.
vector<pair<string, int>>::iterator prev_it(const string& pred,
vector<pair<string, int>> prevpreds) {
vector<pair<string, int>>::reverse_iterator rit;
for(rit = prevpreds.rbegin();
rit != prevpreds.rend(); ++rit) {
if (rit->first == pred) {
return (rit+1).base();}
}
if(rit == prevpreds.rend()) {
return prevpreds.end();
}
}
and in main:
int main() {
vector<pair<string, int>> test;
for(int i = 0; i <= 5; ++i) {
pair<string, int> mypair;
mypair = make_pair("X"+to_string(i%4+1), i+1);
test.emplace_back(mypair);
}
string tpred = "X"+to_string(6);
vector<pair<string, int>>::iterator tit;
tit = prev_it(tpred, test);
if (tit != test.end()) {
cout << tit->first << " " << tit->second << endl;
}
else {cout << "This is the end." << endl;}
}
The code works if tpred is one of X1 to X4. If tpred is X6 (i.e. not an element of test) then I get a segfault. What I would like to be able to do is return the end forward iterator and then, as in main(), have a conditional based on this.
Edit: I am new to c++ (about a year). I am returning a forward iterator because I need to use the iterator later and this seems clearer (but I could be wrong). As far as I understand, a multimap allows non-unique keys but will order the unique keys. I should have been clearer and said time order was important, not key order. I prefer not to use auto while developing because I like to see what I container element/iterator I am using, but point taken.
You're using an iterator of a destructed object. Pass prevpreds by reference, so the iterator maintains valid.
vector<pair<string, int>>::const_iterator prev_it(const string& pred,
const vector<pair<string, int>> &prevpreds)
{
vector<pair<string, int>>::const_reverse_iterator rit;
for (rit = prevpreds.rbegin();
rit != prevpreds.rend(); ++rit)
{
if (rit->first == pred)
{
return (rit + 1).base();
}
}
return prevpreds.end();
}
int main()
{
// ...
vector<pair<string, int>>::const_iterator tit; // <-- uses const iterator
tit = prev_it(tpred, test);
// ...
}

C++: Map, previous item of a key

I have this map: map<int, int > items.
Given a key, I want that this map returns the item corrisponding to the key if it present, otherwise the map returns the item with key immediately less than the given key.
For example, if I have:
items[0]=0;
items[6]=10;
items[15]=18;
items[20]=22;
than for key=15, I want that the map returns item with value 18, otherwise for key=9, I want that map returns item with value 10.
I haven't find a function for this case. But I tried in this way:
itlow=items.lower_bound(key);
if(!items.count(key))
itlow--;
return itlow->second;
This works as I want, entering in the map a min value items[0]=0 for default, but I know that itlow--; it's not good programming. How can I do? thanks all.
You just need to check if your itlow is already items.begin(). If it is, there's no such element in the map:
itlow=items.lower_bound(key);
if(itlow->first == key)
return itlow->second;
else if(itlow != items.begin())
itlow--;
return itlow->second;
else
throw some_exception();
Instead of throwing exception, you may return iterator, and then you can return items.end() if no such element is found.
#include <iostream>
#include <map>
using namespace std;
map<int, int>::const_iterator find(const map<int, int> &items, int value)
{
auto itlow = items.lower_bound(value);
if(itlow->first == value)
return itlow;
else if(itlow != items.cbegin())
return --itlow;
else
return items.cend();
}
int main()
{
map<int, int> items;
items[2]=0;
items[6]=10;
items[15]=18;
items[20]=22;
auto i = find(items, 0);
if(i != items.cend())
{
cout << i->second << endl;
}
i = find(items, 15);
if(i != items.cend())
{
cout << i->second << endl;
}
i = find(items, 9);
if(i != items.cend())
{
cout << i->second << endl;
}
}
Try this
auto it = prev(map.upper_bound(key));
This works because map.upper_bound returns an iterator pointing to the first element that is greater than key or the past-the-end iterator when such element does not exist. Also, OP explained that map is not empty and key is greater than the first element in the map. If the latter conditions are not met, one should handle separately the case where upper_bound returns map.begin().

Elegant way to find closest value in a vector from above

I need a function that takes a vector (assumed to be sorted), and a value, and returns the closest number that's [edit] greater than less than or equal to that number, preferably using an algorithm from the STL. I have come up with a solution using std::lower_bound(), but it seems kludgy and ugly:
struct ClosestCmp {
bool operator()(const int & x, const int & y) { return x > y; }
};
// vec is assumed to be sorted
int closest(const std::vector<int> & vec, int value)
{
std::vector<int>::const_reverse_iterator cri =
std::lower_bound(vec.rbegin(), vec.rend(), value, ClosestCmp());
if (cri != vec.rend()) {
return *cri;
}
return -1;
}
// ...
vec.push_back(1);
vec.push_back(2);
vec.push_back(4);
vec.push_back(5);
std::cout << closest(vec, 2) << "\n"; // Should ouput "2"
std::cout << closest(vec, 3) << "\n"; // Should ouput "2"
std::cout << closest(vec, 4) << "\n"; // Should ouput "4"
Can anyone suggest a way that's more elegant, maybe using an STL algorithm without needing a comparison function or a reverse iterator? I have looked in the STL, but haven't been able to find a better solution than this.
For reminder:
std::lower_bound: returns the first value that does not compare less
std::upper_bound: returns the first value that compares strictly greater
From your description, std::lower_bound already looks like the perfect fit, what is wrong with:
int closest(std::vector<int> const& vec, int value) {
auto const it = std::lower_bound(vec.begin(), vec.end(), value);
if (it == vec.end()) { return -1; }
return *it;
}
Which is used as:
int main() {
std::vector<int> vec;
vec.push_back(2);
vec.push_back(4);
std::cout << closest(vec, 2) << "\n";
std::cout << closest(vec, 3) << "\n";
std::cout << closest(vec, 4) << "\n";
}
Output:
2
4
4
Requires C++11:
template<typename InputIterator, typename ValueType>
InputIterator closest(InputIterator first, InputIterator last, ValueType value)
{
return std::min_element(first, last, [&](ValueType x, ValueType y)
{
return std::abs(x - value) < std::abs(y - value);
});
}
You can only use std::lower_bound and std::upper_bound with binary predicates that match the order of the container. So, you can't sort by < and then use a different binary predicate (say <= or >). So your "kludge" is actually the correct thing to do. The sorted vector in reverse is the ordering criteria you want to use to find the element less than or equal to the value. (Otherwise, if you were actually searching for the value greater than or equal to, you could just use std::lower_bound.)
For the largest which is less or equal one can use this function
int closest(std::vector<int> const& vec, int value) {
auto const it = std::lower_bound(vec.begin(), vec.end(), value);
if (it == vec.begin()) { return -1; }
else return *(it - 1);
}

How to find if a given key exists in a C++ std::map

I'm trying to check if a given key is in a map and somewhat can't do it:
typedef map<string,string>::iterator mi;
map<string, string> m;
m.insert(make_pair("f","++--"));
pair<mi,mi> p = m.equal_range("f");//I'm not sure if equal_range does what I want
cout << p.first;//I'm getting error here
so how can I print what is in p?
Use map::find and map::end:
if (m.find("f") == m.end()) {
// not found
} else {
// found
}
To check if a particular key in the map exists, use the count member function in one of the following ways:
m.count(key) > 0
m.count(key) == 1
m.count(key) != 0
The documentation for map::find says: "Another member function, map::count, can be used to just check whether a particular key exists."
The documentation for map::count says: "Because all elements in a map container are unique, the function can only return 1 (if the element is found) or zero (otherwise)."
To retrieve a value from the map via a key that you know to exist, use map::at:
value = m.at(key)
Unlike map::operator[], map::at will not create a new key in the map if the specified key does not exist.
C++20 gives us std::map::contains to do that.
#include <iostream>
#include <string>
#include <map>
int main()
{
std::map<int, std::string> example = {{1, "One"}, {2, "Two"},
{3, "Three"}, {42, "Don\'t Panic!!!"}};
if(example.contains(42)) {
std::cout << "Found\n";
} else {
std::cout << "Not found\n";
}
}
You can use .find():
map<string,string>::iterator i = m.find("f");
if (i == m.end()) { /* Not found */ }
else { /* Found, i->first is f, i->second is ++-- */ }
C++17 simplified this a bit more with an If statement with initializer.
This way you can have your cake and eat it too.
if ( auto it{ m.find( "key" ) }; it != std::end( m ) )
{
// Use `structured binding` to get the key
// and value.
const auto&[ key, value ] { *it };
// Grab either the key or value stored in the pair.
// The key is stored in the 'first' variable and
// the 'value' is stored in the second.
const auto& mkey{ it->first };
const auto& mvalue{ it->second };
// That or just grab the entire pair pointed
// to by the iterator.
const auto& pair{ *it };
}
else
{
// Key was not found..
}
m.find == m.end() // not found
If you want to use other API, then find go for m.count(c)>0
if (m.count("f")>0)
cout << " is an element of m.\n";
else
cout << " is not an element of m.\n";
I think you want map::find. If m.find("f") is equal to m.end(), then the key was not found. Otherwise, find returns an iterator pointing at the element found.
The error is because p.first is an iterator, which doesn't work for stream insertion. Change your last line to cout << (p.first)->first;. p is a pair of iterators, p.first is an iterator, p.first->first is the key string.
A map can only ever have one element for a given key, so equal_range isn't very useful. It's defined for map, because it's defined for all associative containers, but it's a lot more interesting for multimap.
template <typename T, typename Key>
bool key_exists(const T& container, const Key& key)
{
return (container.find(key) != std::end(container));
}
Of course if you wanted to get fancier you could always template out a function that also took a found function and a not found function, something like this:
template <typename T, typename Key, typename FoundFunction, typename NotFoundFunction>
void find_and_execute(const T& container, const Key& key, FoundFunction found_function, NotFoundFunction not_found_function)
{
auto& it = container.find(key);
if (it != std::end(container))
{
found_function(key, it->second);
}
else
{
not_found_function(key);
}
}
And use it like this:
std::map<int, int> some_map;
find_and_execute(some_map, 1,
[](int key, int value){ std::cout << "key " << key << " found, value: " << value << std::endl; },
[](int key){ std::cout << "key " << key << " not found" << std::endl; });
The downside to this is coming up with a good name, "find_and_execute" is awkward and I can't come up with anything better off the top of my head...
map<string, string> m;
check key exist or not, and return number of occurs(0/1 in map):
int num = m.count("f");
if (num>0) {
//found
} else {
// not found
}
check key exist or not, and return iterator:
map<string,string>::iterator mi = m.find("f");
if(mi != m.end()) {
//found
//do something to mi.
} else {
// not found
}
in your question, the error caused by bad operator<< overload, because p.first is map<string, string>, you can not print it out. try this:
if(p.first != p.second) {
cout << p.first->first << " " << p.first->second << endl;
}
Be careful in comparing the find result with the the end like for map 'm' as all answer have
done above
map::iterator i = m.find("f");
if (i == m.end())
{
}
else
{
}
you should not try and perform any operation such as printing the key or value with iterator i if its equal to m.end() else it will lead to segmentation fault.
Comparing the code of std::map::find and std::map::count, I'd say the first may yield some performance advantage:
const_iterator find(const key_type& _Keyval) const
{ // find an element in nonmutable sequence that matches _Keyval
const_iterator _Where = lower_bound(_Keyval); // Here one looks only for lower bound
return (_Where == end()
|| _DEBUG_LT_PRED(this->_Getcomp(),
_Keyval, this->_Key(_Where._Mynode()))
? end() : _Where);
}
size_type count(const key_type& _Keyval) const
{ // count all elements that match _Keyval
_Paircc _Ans = equal_range(_Keyval); // Here both lower and upper bounds are to be found, which is presumably slower.
size_type _Num = 0;
_Distance(_Ans.first, _Ans.second, _Num);
return (_Num);
}
I know this question already has some good answers but I think my solution is worth of sharing.
It works for both std::map and std::vector<std::pair<T, U>> and is available from C++11.
template <typename ForwardIterator, typename Key>
bool contains_key(ForwardIterator first, ForwardIterator last, Key const key) {
using ValueType = typename std::iterator_traits<ForwardIterator>::value_type;
auto search_result = std::find_if(
first, last,
[&key](ValueType const& item) {
return item.first == key;
}
);
if (search_result == last) {
return false;
} else {
return true;
}
}
map <int , char>::iterator itr;
for(itr = MyMap.begin() ; itr!= MyMap.end() ; itr++)
{
if (itr->second == 'c')
{
cout<<itr->first<<endl;
}
}
If you want to compare pair of map you can use this method:
typedef map<double, double> TestMap;
TestMap testMap;
pair<map<double,double>::iterator,bool> controlMapValues;
controlMapValues= testMap.insert(std::pair<double,double>(x,y));
if (controlMapValues.second == false )
{
TestMap::iterator it;
it = testMap.find(x);
if (it->second == y)
{
cout<<"Given value is already exist in Map"<<endl;
}
}
This is a useful technique.