So I have a set of pairs<string ,string>
And I want to use find() to search for a single string which would be in the "first" of the pair, then if I find that string in first I want to return second from that function.
My current attempt is..
myList::iterator i;
i = theList.find(make_pair(realName, "*"));
return i->second;
Is C++11 acceptable?
auto it = find_if(theList.begin(), theList.end(),
[&](const pair<string, string>& val) -> bool {
return val.first == realName;
});
return it->second;
Or in C++03, first define a functor:
struct MatchFirst
{
MatchFirst(const string& realName) : realName(realName) {}
bool operator()(const pair<string, string>& val) {
return val.first == realName;
}
const string& realName;
};
then call it like so:
myList::iterator it = find_if(a.begin(), a.end(), MatchFirst(realName));
return it->second;
This will only return the first match, but from your question, it looks like that's all you're expecting.
You can use std::set<std::pair<std::string, std::string> > for this but you will need a custom
comparison object for this because the pair's relational operator takes both elements for this. That said, it seems as if you actually should use a std::map<std::string, std::string> instead.
The definition of < for std::pair implements a lexicographical order and "" is the minimum element for strings. Combining this we get:
typedef std::pair<std::string, std::string> StringPair;
typedef std::set<StringPair> Set;
std::string const* find_first(Set const& s, std::string const& key) {
Set::const_iterator const it = s.lower_bound(std::make_pair(key, ""));
// Check that it actually points to a valid element whose key is of interest.
if (it == s.end() or it->first != key) { return 0; }
// Yata!
return &it->second;
}
The trick is using lower_bound appropriately.
Returns an iterator pointing to the first element which does not compare less than value.
If it returns end(), then it did not find anything interesting.
Otherwise, it->first >= key so we get rid of the > case (of no interest to us)
I would point out though that this only returns the first element of the range. If you are interested in all elements, try:
typedef std::pair<Set::const_iterator, Set::const_iterator> SetItPair;
SetItPair equal_range_first(Set const& s, std::string const& key) {
StringPair const p = std::make_pair(key, "");
return std::make_pair(s.lower_bound(p), s.upper_bound(p));
}
This will return the full range of nodes in s whose first element is equal to key. You then just have to iterate over this range:
for (Set::const_iterator it = range.first; it != range.second; ++it) {
// do something
}
And you don't even have to worry whether the return of lower_bound or upper_bound was end or not.
if lower_bound returns end(), then so does upper_bound, and the loop is skipped
if lower_bound points to a node for which it->first > key, then upper_bound will point to that same node, and the loop is skipped
That is the power of ranges: no need to make special checks, the ranges just end up empty when there is no match, and so the loop over them... is skipped in a single check.
Related
How do you find the substring within a string in the key of a multimap? For example, if I enter "Louis," then Louisville, Louisberg, and StLouis are found?
For what you want to do you will have to search within each and every key, not just the prefix or suffix. I don't think there's any way round that and it cannot be optimised since the search term can occur anywhere within the key.
You can use std::find_if and supply a predicate function for matching elements and iterate your map. I am using std::map in the code below but this could apply for a std::multimap too.
#include <map>
#include <string>
#include <algorithm>
#include <iostream>
int main()
{
std::map<std::string, std::string> myMap{
{"Louis", "AA"}, {"Louisville", "BBB"}, {"Louisberg", "A"},
{"StLouis ", "C"}, {"Huntsville", "D"} };
std::string term("Louis");
auto keyContains = [&term](const std::pair<std::string, std::string>& item)
{
return item.first.find(term) != std::string::npos;
};
auto iter = std::find_if(myMap.begin(), myMap.end(), keyContains);
while (iter != myMap.end())
{
std::cout << iter->first << std::endl;
iter = std::find_if(std::next(iter), myMap.end(), keyContains);
}
}
keyContains is lambda function. If you're not familiar with lambda functions you can use a functor instead:
struct keyContains
{
keyContains(const std::string& searchTerm) : mSearchTerm(searchTerm) {}
bool operator() (const std::pair<std::string, string>& item) const
{
return item.first.find(mSearchTerm) != std::string::npos;
}
std::string mSearchTerm;
};
Then initialise it like this: keyContains comp("Louis") and pass comp as the predicate.
Hope this is helpful? It's effectively a for loop that walks the map. Working version here.
Update:
I just read your comment where you say your search should return 54049 results. That's a lot of records! To do that it is better to match against prefix or suffix. You can use std::map::lower_bound() and std::map::upper_bound().
Why bother with a multimap for that?
std::string search_term = "Louis";
std::unordered_set<std::string> data = { "Louisville", "Louisberg", "StLouis" };
for (std::string const& each : data) {
if (std::find(each.begin(), each.end(), search_term) != std::string::npos) {
// contains it
}
}
That would be a good option I believe, if you really have to use a multimap then doing substrings of keys is kind of hard, since that's not what they're made for
I have a collection of object of type "T" that i want to iterate through. An object of type "T" has two important properties:
int r; // row number
int c; // column number
I would like to define an iterator that allows me to iterate through all elements of the collection.
This can be done using:
std::vector<T> v;
for(std::vector<T>::iterator it = v.begin(); it != v.end(); ++it) {
....
}
However, I would like the iterator to have one more property. I would like to be able to call
it.nextrow()
calling this function should return the element "e" of v where e.r + 1 = ec.r and e.c = ec.c, where ec is the current element pointed by the iterator. I.e. calling it.nextrow() should give me a pointer to the element where column is the same, but row is incremented by one. Hope it makes sense.
I am not sure what I need to do in order for this to work, as I am fairly new to advanced c++ concepts. Can anybody help me?
Not everything has to be a member function. Would you accept a iterator nextRow(iterator current, iterator begin, iterator end) free function?
template<typename Iterator>
Iterator nextRow(Iterator needle, Iterator begin, Iterator end)
{
return std::find_if(begin, end, [needle](const T & elem) { return (elem.r == needle->r + 1) && (elem.c == needle->c); });
}
If your vector is always sorted, you don't need a separate begin, just use needle.
If you do need this to be a part of a wrapper iterator, that type will need to contain a begin and end.
template <typename Iterator>
class SearchableIterator
{
Iterator wrapped, begin, end;
public:
difference_type Iterator::difference_type;
value_type Iterator::value_type;
pointer Iterator::pointer;
reference Iterator::reference
iterator_category Iterator::iterator_category
SearchableIterator(Iterator wrapped, Iterator begin, Iterator end)
: wrapped(wrapped), begin(begin), end(end) {}
// All the members, calling that member of wrapped (see std::reverse_iterator for guidance)
SearchableIterator nextRow()
{
return SearchableIterator(std::find_if(begin, end, [this](const T & elem) { return (elem.r == wrapped->r + 1) && (elem.c == wrapped->c); }), begin, end);
}
}
Iterators are copyable.
You can
derive from the container's iterator for your container,
add construction from the container's iterator,
add your extra property members,
and declare that begin(), end(), etc from your custom container return your derived iterator.
Assuming your data are packed in a vector with consecutive items for all columns of a row followed by items of the next row, you would just need *(iterator + column_count) to access the next-row-same-column value (don't try this on an iterator that's already pointing into the last row of data)
You can create a wrapper iterator similar to Implement custom iterator for c++ std container and give it a specific column count as additional information:
template<typename T, int colsize, typename TIterator = std::vector<T>::iterator>
class MyRowIterator : public std::iterator<std::forward_iterator_tag, T>
{
private:
TIterator m_pter;
public:
MyRowIterator(TIterator& value): m_pter(value)
{
}
MyRowIterator(const MyRowIterator& other_it): m_pter(other_it.m_pter)
{
}
MyRowIterator& operator++()
{
++m_pter;
return *this;
}
bool operator!=(const MyRowIterator& rhs)
{
return m_pter != rhs.m_pter;
}
T& operator*()
{
return (*m_pter);
}
// here it is
T& nextrow()
{
return *(m_pter+colsize);
}
};
Usage example:
void Test()
{
std::vector<int> data;
// 2 rows each 10 columns
data.resize(20);
for (auto& item : data)
{
item = 0;
}
data[2] = 1;
data[12] = 5;
// don't iterate the last line, else nextrow() will access out of bounds!
for (MyRowIterator<int, 10> iter = data.begin(); iter != (data.end()-10); iter++)
{
std::cout << *iter << " # " << iter.nextrow() << std::endl;
}
}
I have vector of pair like this:
std::vector < std::pair < int /*Val1*/, int /*Val2*/ > > myVector;
What is the efficient way to compare for each pair in 'myVector' first and second element of pair (Val1 and Val2) are same or not.
The only way I could think of is -
bool IsFirstAndSecondSame(vector<pair<T, T>> myVector)
{
for(auto valuePair : myVector)
{
if(valuePair.first != valuePair.second)
return false'
}
return true;
}
Although in example I have used pair of integers, the question is about any pair having first and second element of same type.
Although in example I have used pair of integers, the question is about any pair having first and second element of same type.
You're probably asking about using a templated function like this:
template<typename T>
bool IsFirstAndSecondSame(const vector<pair<T, T>>& myVector) // const
// ^^^^^
// makes no sense
// with free functions
{
for(const auto& valuePair : myVector)
{
if(valuePair.first != valuePair.second)
return false'
}
return true;
}
I have this simple code:
std::vector<std::map<double,double>> v;
//populate v
//we know each map already has correct key order (enforced by c++)
//but i also want to make sure the different maps have correct key order
//this is how I do it using a pointer:
const double *last_key = nullptr;
for (const auto &map : v)
{
if (map.size() > 0) //ignore empty maps
{
if (last_key)
{
const auto &new_key = map.cbegin()->first;
if (!(*last_key < new_key))
throw std::runtime_error("invalid key order");
}
last_key = &(--map.cend())->first;
}
}
Is this a good use for pointers? How would you do it instead?
The only real alternative I know (if I want to avoid pointers) is to do this:
double last_key;
bool last_key_has_been_set = false;
This works, but it requires that the key is default constructible and it involves unnecessary copying of keys (problem for different key types than double).
OK, since I now (think I) understand what your code is about, here's my take on it:
auto iter = v.begin();
auto end = v.end();
while (iter != end && iter->empty())
++iter;
if (iter != end)
{
while (true) // loop and a half
{
auto next = iter+1; // at this point, we know iter != end
while (next != end && next->empty())
++next;
if (next == end)
break;
auto lhslast = lhs.end();
--lhslast;
if (lhslast->first > next->begin()->first)
throw std::runtime_error("invalid key order");
iter = next;
}
}
Edit:
The code above can be further improved using another algorithm:
Replace
while (iter != end && iter->empty())
++iter;
with
iter = std::find_if(iter, end,
[](std::map<double, double> const& m) { return m.empty(); });
and analogous for the next loop.
Another option is to notice that if it were not empty maps, you could just use adjacent_find. Therefore another option is to make use of Boost's filter_iterator to get rid of the empty maps. Thus do
#include <boost/iterator/filter_iterator.hpp>
struct is_not_empty
{
template<typename Container> bool operator()(Container const& c) const
{
return !c.empty();
}
};
and then at the place of your code
auto fbegin = boost::make_filter_iterator(is_not_empty(), v.begin(), v.end());
auto fend = boost::make_filter_iterator(is_not_empty(), v.end(), v.end());
if (std::adjacent_find(fbegin, fend,
[](std::map<double, double> const& lhs,
std::map<double, double> const& rhs) -> bool
{
auto lhslast = lhs.end();
--lhslast;
return lhslast->first > rhs.begin()->first;
}) != fend)
throw std::runtime_error("invalid key order");
The filter iterator makes sure that only the non-empty maps are considered.
I don't think there is a suitable predefined algorithm in the standard library that does this. In particular, std::adjacent_find could be used for this if you were to define a relatively complex and stateful predicate for it, but that would really amount to misusing std::adjacent_find as some kind of replacement for std::for_each, i.e. it would not have much to do with the original purpose of std::adjacent_find.
However, instead of naked pointers, you should be using iterators. I'd also suggest putting the checking code into a separate function, perhaps named check. Here is what I would suggest:
#include <vector>
#include <map>
#include <iostream>
bool check(const std::vector<std::map<double,double>> &v)
{
/* Fast-forward to the first non-empty entry. */
auto it = begin(v);
for( ; it != end(v) ; ++it)
if (!it->empty())
break;
/* We might be done by now. */
if (it == end(v))
return true;
/* Else, go through the remaining entries,
skipping empty maps. */
auto prev = it->end();
advance(prev,-1);
++it;
for ( ; it != end(v) ; ++it)
{
if (!it->empty())
{
if (it->begin()->first < prev->first)
return false;
prev = it->end();
advance(prev,-1);
}
}
return true;
}
int main()
{
std::vector<std::map<double,double>> v;
/* Two entries for the vector, invalid order. */
v.push_back({ {1.0,1.0} , {2.0,4.0} });
v.push_back({ {3.0,9.0} , {1.0,16.0} });
if (!check(v))
throw std::runtime_error("Invalid order of the maps in the vector.");
return 0;
}
Note: It would be even more C++-like (or, at least more like the algorithms in the standard library) if you were to define the check function as an algorithm that takes a range of iterators, rather than a reference to a container, as argument. Rewriting the function to match this concept is straight-forward.
Note 2: The advantage of using iterators instead of naked pointers is that you get a better and cleaner abstraction of what you need: Something that references an item in the map, whereas a double* pointer could be pointing to all kinds of things. However, there is also a disadvantage of using iterators: If you were to modify your algorithm such that it alters maps while iterating through the vector, the iterator may be invalidated, whereas the pointer would not (unless you delete the element it points to). (The pointers might be invalidated if you alter the vector, though.)
But as long as the checking procedure is only used for checking and nothing else (which my code indicates by putting the code into a separate function dedicated to this purpose, and by taking the vector as a const-reference), iterator invalidation is not an issue.
This uses a C++1y feature (std::tr2::optional), but should work with any container and any ordering on the elements of the containers:
struct compare_key_order {
template<typename LHS, typename RHS>
bool operator()( LHS const& lhs, RHS const& rhs ) {
return lhs.first < rhs.first;
}
};
template<typename ContainerOfContainers, typename Ordering>
bool are_container_endpoints_ordered( ContainerOfMaps&& meta, Ordering&& order=compare_key_order() )
{
using std::begin; using std::end;
// or boost::optional:
std::tr2::optional< decltype( begin(begin(meta)) ) > last_valid;
for( auto&& Map : std::forward<Meta>(meta) ) {
auto b = begin(Map);
auto e = end(Map);
if (b==e)
continue;
if (last_valid)
if (!order( **last_valid, *b ))
return false;
last_valid = e;
}
return true;
}
optional is a prettier, less error prone way of dealing with the "this element may or may not exist" than a pointer-that-can-be-nullptr. If you are using boost or have access to a std::tr2::optional (or you are reading this in the future, when std::optional exists), it is a better idea than a pointer.
You could also move the "is there a last_valid out of state and into program code location:
struct compare_key_order {
template<typename LHS, typename RHS>
bool operator()( LHS const& lhs, RHS const& rhs ) {
return lhs.first < rhs.first;
}
};
template<typename ContainerOfContainers, typename Ordering>
bool are_container_endpoints_ordered( ContainerOfMaps&& meta, Ordering&& order=compare_key_order() )
{
using std::begin; using std::end;
auto it = begin(meta);
while( it != end(meta) && (begin(*it) == end(*it)) {
++it;
}
if ( it == end(meta) )
return true;
auto last_valid_end = end(*it);
for( ++it; it != end(meta); ++it ) {
auto b = begin(*it);
auto e = end(*it);
if (b==e)
continue;
if (!order( *last_valid_end, *b ))
return false;
last_valid = e;
}
return true;
}
this would let the same algorithm run on vectors-of-vectors-of-pairs, or even check if vectors-of-vectors have sorted endpoints (with a different order).
Best noted comment gives the answer : use adjacent_find.
First a little bit of logic. If there is n < m indexes verifying key[n] > key[m], then an index i exists, n <= i < m where key[i] > key[i+i].
You can demonstrate this with absurdity reasoning : If there is no such i, then for all i between n and m we have order, and because order relation is transitive, key[n] <= key[m] : absurd.
This means, ignoring the empty maps, if you have bad order on your keys, then you have two adjacent keys in bad order.
So your algorithm shoud be:
typedef map<double, double> map_t;
vector<map_t> v;
remove_if(v.begin(), v.end(), [](map_t const& m){return m.empty();});
if(adjacent_find(v.begin(), v.end(), [](map_t const& l, map_t const& r)
{
return (--l.cend())->first > r.cbegin()->first;
}) != v.end())
throw std::runtime_error("invalid key order");
This is, of course, if you can remove the empty maps from your vector first. (we can assume that, as empty maps may not be so meaningful, but it depends on the whole situation, for sure).
I came across the following code snippet in C++ (I am not yet on C++11):
int test(std::map<int, size_t> &threshold, const int value) {
std::map<int, size_t>::const_iterator itr = threshold.upper_bound(value);
if (threshold.begin() == itr) {
return -1;
}
return return (--itr)->second;
}
In particular, I do not like the use of --itr at the end nor the compare of itr to begin(), they both feel wrong to me.
I'm wondering if there is a way with STL to do some kind of lookup that would return end() (or rend()) if not found and otherwise to return the last element that is less than or equal to the value so the code would look more like this:
int test(std::map<int, size_t> &threshold, const int value) {
std::map<int, size_t>::const_reverse_iterator itr = threshold.WhatGoesHere(value);
if (threshold.rend() == itr) {
return -1;
}
return return itr->second;
}
In a sense, I want a reverse_lower_bound() that returns a reverse iterator to the last element that is not greater than the value or if none can be found rend().
Based on Xeo's comment, I think this is the answer:
int test(std::map<int, size_t> &threshold, const int value) {
std::map<int, size_t>::const_reverse_iterator
last_element_not_greater_than(threshold.upper_bound(value));
if (threshold.rend() == last_element_not_greater_than) {
return -1;
}
return return last_element_not_greater_than->second;
}
I learned this new thing:
When an iterator is reversed, the reversed version does not point to the same
element in the range, but to the one preceding it.