Find an element of vector which is presented in the map - boost

I need to find an element of vector which is presented in map. Hard part is that vector consists of structures, so you should call member function to extract value form the structure first to compare it to the map elements.
So, with for cycle it's pretty easy:
vector<A>::iterator it;
for( it = vec.begin(); it != vec.end(); ++it )
{
if( mp.count( it->getKey() ) )
{
break;
}
}
My question: is there any way to do it in one line, something like
//this doesn't work as count accepts key_type
vector<A>::iterator it = find_if( vec.begin(), vec.end(), boost::bind( &map<string, string>::count, mp, boost::bind( &A::getKey, _1 ) )) != 0);
Full example, to test
#include <string>
#include <vector>
#include <iostream>
#include <algorithm>
#include <boost/bind.hpp>
#include <boost/assign.hpp>
using namespace std;
class A{
public:
A( const std::string& key )
: key( key ) {}
std::string getKey(){ return key; }
private:
std::string key;
};
int main(int argc, const char *argv[]) {
map<string, string> mp = boost::assign::map_list_of( "Key1", "Val1" ) ( "Key2", "Val2" ) ( "Key3", "Val3" );
vector<A> vec = boost::assign::list_of( "AAA" ) ( "Key2" ) ( "BBB" );
// vector<A>::iterator it = find_if( vec.begin(), vec.end(), boost::bind( &map<string, string>::count, mp, boost::bind( &A::getKey, _1 ) )) != 0);
vector<A>::iterator it;
for( it = vec.begin(); it != vec.end(); ++it )
{
if( mp.count( it->getKey() ) )
{
break;
}
}
cout << ( it != vec.end() ? "found" : "not found" ) << endl;
return 0;
}
Thanks in advance

Your solution was close, there is just one closing parenthesis too many. Placing each parenthesis on a newline with indenting for each level emphasizes the invalid parenthesis:
vector<A>::iterator it = find_if
(
vec.begin(), vec.end(), boost::bind
(
&map<string, string>::count, &mp, boost::bind
(
&A::getKey, _1
)
)
) // one too many
!= 0);
In its simplest form, the line becomes iterator = find_if(...) != 0), which will cause the compiler to fail on either:
Not being able to find operator!=(iterator, int).
The ) token in != 0).
With correct parentheses, != 0 uses an operator overload provided by boost::bind. The line would look like:
vector<A>::iterator it = find_if(vec.begin(), vec.end(),
boost::bind(&map<string, string>::count, &mp,
boost::bind(&A::getKey, _1)) != 0);
However, consider the readability of such a simple operation. If a simple for loop is not generic and reusable enough, then consider hiding it within a convenience function:
template <typename InputIterator,
typename C,
typename Fn>
InputIterator find_if_contains(
InputIterator first,
InputIterator last,
const C& container,
Fn fn)
{
while (first != last)
{
if (0 != container.count(fn(*first))) return first;
++first;
}
return last;
}
...
vector<A>::iterator it = find_if_contains(
vec.begin(), vec.end(),
mp, boost::bind(&A::getKey, _1)
);
Otherwise, a custom predicate type may enhance readability while providing some extra flexibility for reuse with different types. For example, consider the following predicate type that works for various types of associative containers:
template <typename C,
typename Fn>
struct contains_predicate
{
contains_predicate(const C& container, Fn fn)
: container_(&container), fn_(fn)
{}
template <typename T>
bool operator()(T& t)
{
return 0 != container_->count(fn_(t));
}
const C* container_;
Fn fn_;
};
template <typename C,
typename Fn>
contains_predicate<C, Fn>
contains(const C& container, Fn fn)
{
return contains_predicate<C, Fn>(container, fn);
}
...
vector<A>::iterator it = find_if(vec.begin(), vec.end(),
contains(mp, boost::bind(&A::getKey, _1)));

In C++11, use a lambda:
find_if(vec.begin(), vec.end(), [&](A const & a){return mp.count(a.getKey());});
But since you're using Boost.Assign rather than uniform initialisation, perhaps you can't do that. I'm afraid I don't know how to construct a functor like that using bind alone.

Related

what is the purpose of template class in c++

I cannot understand what is template class used for?
I am new to c++. Can I get a detail explanation.
// constructing unordered_sets
#include <iostream>
#include <string>
#include <unordered_set>
template<class T>
T cmerge (T a, T b) { T t(a); t.insert(b.begin(),b.end()); return t; }
std::unordered_set<std::string> second ( {"red","green","blue"} ); // init list
std::unordered_set<std::string> third ( {"orange","pink","yellow"} ); // init list
std::unordered_set<std::string> fourth ( second );
std::unordered_set<std::string> fifth ( cmerge(third,fourth) ); // move
C++ template class/function is basically a generic class/function i.e., you just have to define the class or function once and you can use this definition for different data types(int,char,float etc).
for Example:-
#include <iostream>
using namespace std;
// One function works for all data types. This would work
// even for user defined types if operator '>' is overloaded
template <typename T>
T myMax(T x, T y)
{
return (x > y)? x: y;
}
int main()
{
cout << myMax<int>(3, 7) << endl; // Call myMax for int
cout << myMax<double>(3.0, 7.0) << endl; // call myMax for double
cout << myMax<char>('g', 'e') << endl; // call myMax for char
return 0;
}

using range based for loop for iterating on a sub range

Is it possible to loop over sub range using range based for loop ?
std::vector <std::string> inputs={"1","abaaaa","abc","cda"};
for (auto &it : new_vector(inputs.begin()+1, inputs.end()))
{
// …
}
You could use Boost's iterator_range:
for (auto &it : boost::make_iterator_range(inputs.begin()+1, inputs.end()))
{
cout << it << endl;
}
demo
Alternatively you could write your own wrapper.
Unfortunately, there is no such thing in the C++ standard library. However, you can define your own wrapper like this (requires at least C++ 11 - which should not be problem in 2021):
template<typename Iter>
struct range
{
Iter b, e;
Iter begin() const { return b; }
Iter end() const { return e; }
};
template<typename T>
auto slice(const T& c, std::size_t from, std::size_t to = -1) -> range<decltype(c.begin())>
{
to = (to > c.size() ? c.size() : to);
return range<decltype(c.begin())>{c.begin() + from, c.begin() + to};
}
And then you can use it:
std::vector<int> items(100);
// Iterates from 4th to 49th item
for (auto x: slice(items, 4, 50))
{
}
// Iterates from 15th to the last item
for (auto x: slice(items, 15))
{
}
tl;dr
Long story short, you #include <range/v3/view/subrange.hpp> and change your new_vector to ranges::subrange. And that's it. Demo on Compiler Explorer.
So
Given the name you imagine for this function, new_vector, maybe you think you need the entity on the right of : to be a std::vector or at least some type of container.
If that's the case, then change your mind, it's not needed. All that : wants from its "right hand side" is that it have begin and end defined on them, member or non member. For instance, this compiles and runs just fine:
struct A {};
int* begin(A);
int* end(A);
struct B {
int* begin();
int* end();
};
int main()
{
for (auto it : A{}) {}
for (auto it : B{}) {}
}

How to skip the first element of the vector and iterate from second using range based for loops [duplicate]

I have a std::vector<std::string> v; (initialized). How can I use the range-for loop for accessing all elements except the first one (on index zero). For all elements:
for (const string & s: v)
process(s);
Instead of the v a range expression can be used. How can I write the range expression to skip the first element (or skip the first n elements)?
I know how to get the effect using v.begin() + 1 and using the classic loop. I am searching for the new, more readable, recommended alternative to do that. Possibly something similar to Python slicing? ...like:
for s in v[1:]:
process(s)
Until ranges make it into the standard library, you won't get any better than a vanilla for loop in plain C++ :
for(auto i = begin(v) + 1, e = end(v); i !=e; ++i)
// Do something with *i
Create a wrapper for which begin() and end() return the correct iterators and then you can use that as the second argument.
#include <iostream>
#include <vector>
template< typename Collection >
class FromNth
{
Collection& coll_;
size_t offset_;
public:
FromNth( Collection& coll, size_t offset )
: coll_( coll ), offset_( offset )
{
}
// will nicely resolve to const_iterator if necessary
auto begin() const -> decltype( coll_.begin() )
{ return coll_.begin() + offset_; }
auto end() const -> decltype( coll_.end() )
{ return coll_.end(); }
};
template< typename Collection >
FromNth<Collection> makeFromNth( Collection& collection, size_t offset )
{
return FromNth<Collection>( collection, offset );
}
template< typename Collection >
auto begin( const FromNth<Collection> & wrapper ) -> decltype( wrapper.begin() )
{
return wrapper.begin();
}
template< typename Collection >
auto end( const FromNth<Collection> & wrapper ) -> decltype( wrapper.end() )
{
return wrapper.end();
}
int main()
{
std::vector< int > coll { 2, 3, 5, 7, 11, 13, 17, 19, 23 };
for( auto x : makeFromNth( coll, 1 ) )
{
std::cout << x << '\n';
}
return 0;
}
Note that my fromNth "begin" is undefined behaviour if the size of the input is less than the offset. (If it's equal then it's well defined and begin == end). Therefore do a size check first.
Note: if you are using a recent enough version of boost then iterator_range may already provide you such a "collection" that is similar to my "FromNth".
for( auto const& s : boost::make_iterator_range( v.begin() + 1, v.end() ) )
{
process( s );
}
Note: the code above worked on CodingGround using C++11 GNU 4.8.3. (That site is very slow though). From C++14 you will not need the ->decltype statements (which are needed in C++11 for templates).
Output:
sh-4.3$ g++ -std=c++11 -o main *.cpp
sh-4.3$ main
3
5
7
11
13
17
19
23

iterator over non-existing sequence

I have K objects (K is small, e.g. 2 or 5) and I need to iterate over them N times in random order where N may be large. I need to iterate in a foreach loop and for this I should provide an iterator.
So far I created a std::vector of my K objects copied accordingly, so the size of vector is N and now I use begin() and end() provided by that vector. I use std::shuffle() to randomize the vector and this takes up to 20% of running time. I think it would be better (and more elegant, anyways) to write a custom iterator that returns one of my object in random order without creating the helping vector of size N. But how to do this?
It is obvious that your iterator must:
Store pointer to original vector or array: m_pSource
Store the count of requests (to be able to stop): m_nOutputCount
Use random number generator (see random): m_generator
Some iterator must be treated as end iterator: m_nOutputCount == 0
I've made an example for type int:
#include <iostream>
#include <random>
class RandomIterator: public std::iterator<std::forward_iterator_tag, int>
{
public:
//Creates "end" iterator
RandomIterator() : m_pSource(nullptr), m_nOutputCount(0), m_nCurValue(0) {}
//Creates random "start" iterator
RandomIterator(const std::vector<int> &source, int nOutputCount) :
m_pSource(&source), m_nOutputCount(nOutputCount + 1),
m_distribution(0, source.size() - 1)
{
operator++(); //make new random value
}
int operator* () const
{
return m_nCurValue;
}
RandomIterator operator++()
{
if (m_nOutputCount == 0)
return *this;
--m_nOutputCount;
static std::default_random_engine generator;
static bool bWasGeneratorInitialized = false;
if (!bWasGeneratorInitialized)
{
std::random_device rd; //expensive calls
generator.seed(rd());
bWasGeneratorInitialized = true;
}
m_nCurValue = m_pSource->at(m_distribution(generator));
return *this;
}
RandomIterator operator++(int)
{ //postincrement
RandomIterator tmp = *this;
++*this;
return tmp;
}
int operator== (const RandomIterator& other) const
{
if (other.m_nOutputCount == 0)
return m_nOutputCount == 0; //"end" iterator
return m_pSource == other.m_pSource;
}
int operator!= (const RandomIterator& other) const
{
return !(*this == other);
}
private:
const std::vector<int> *m_pSource;
int m_nOutputCount;
int m_nCurValue;
std::uniform_int_distribution<std::vector<int>::size_type> m_distribution;
};
int main()
{
std::vector<int> arrTest{ 1, 2, 3, 4, 5 };
std::cout << "Original =";
for (auto it = arrTest.cbegin(); it != arrTest.cend(); ++it)
std::cout << " " << *it;
std::cout << std::endl;
RandomIterator rndEnd;
std::cout << "Random =";
for (RandomIterator it(arrTest, 15); it != rndEnd; ++it)
std::cout << " " << *it;
std::cout << std::endl;
}
The output is:
Original = 1 2 3 4 5
Random = 1 4 1 3 2 4 5 4 2 3 4 3 1 3 4
You can easily convert it into a template. And make it to accept any random access iterator.
I just want to increment Dmitriy answer, because reading your question, it seems that you want that every time that you iterate your newly-created-and-shuffled collection the items should not repeat and Dmitryi´s answer does have repetition. So both iterators are useful.
template <typename T>
struct RandomIterator : public std::iterator<std::forward_iterator_tag, typename T::value_type>
{
RandomIterator() : Data(nullptr)
{
}
template <typename G>
RandomIterator(const T &source, G& g) : Data(&source)
{
Order = std::vector<int>(source.size());
std::iota(begin(Order), end(Order), 0);
std::shuffle(begin(Order), end(Order), g);
OrderIterator = begin(Order);
OrderIteratorEnd = end(Order);
}
const typename T::value_type& operator* () const noexcept
{
return (*Data)[*OrderIterator];
}
RandomIterator<T>& operator++() noexcept
{
++OrderIterator;
return *this;
}
int operator== (const RandomIterator<T>& other) const noexcept
{
if (Data == nullptr && other.Data == nullptr)
{
return 1;
}
else if ((OrderIterator == OrderIteratorEnd) && (other.Data == nullptr))
{
return 1;
}
return 0;
}
int operator!= (const RandomIterator<T>& other) const noexcept
{
return !(*this == other);
}
private:
const T *Data;
std::vector<int> Order;
std::vector<int>::iterator OrderIterator;
std::vector<int>::iterator OrderIteratorEnd;
};
template <typename T, typename G>
RandomIterator<T> random_begin(const T& v, G& g) noexcept
{
return RandomIterator<T>(v, g);
}
template <typename T>
RandomIterator<T> random_end(const T& v) noexcept
{
return RandomIterator<T>();
}
whole code at
http://coliru.stacked-crooked.com/a/df6ce482bbcbafcf or
https://github.com/xunilrj/sandbox/blob/master/sources/random_iterator/source/random_iterator.cpp
Implementing custom iterators can be very tricky so I tried to follow some tutorials, but please let me know if something have passed:
http://web.stanford.edu/class/cs107l/handouts/04-Custom-Iterators.pdf
https://codereview.stackexchange.com/questions/74609/custom-iterator-for-a-linked-list-class
Operator overloading
I think that the performance is satisfactory:
On the Coliru:
<size>:<time for 10 iterations>
1:0.000126582
10:3.5179e-05
100:0.000185914
1000:0.00160409
10000:0.0161338
100000:0.180089
1000000:2.28161
Off course it has the price to allocate a whole vector with the orders, that is the same size of the original vector.
An improvement would be to pre-allocate the Order vector if for some reason you have to random iterate very often and allow the iterator to use this pre-allocated vector, or some form of reset() in the iterator.

c++11 insert into collection with a lambda functional map

It is kind of exasperating that std collections don't provide a functional map interface to fill a collection
std::vector< int > oldV = {1,3,5};
std::vector< int > newV = (oldV % [&](int v)-> int{ return v+1; });
newV.insert( oldV.begin(), oldV.end(), [&](int v)-> int{ return 2*v; });
Is there a simple header library that implements wrappers for functional style programming with std collections?
I don't see a way to do it such that it would apply both to things like std::vector and std::unordered_set without repeating the operator definition for each container. In the case of vector it would be like this:
#include <iostream>
#include <vector>
template <typename T, typename Lambda>
std::vector< T > operator |(const std::vector< T >& input, Lambda map)
{
std::vector< T > output;
for (const T& elem : input)
output.push_back( map(elem) );
return std::move(output);
};
int main()
{
std::vector< int > oldV = {1,3,5};
std::vector< int > newV = oldV | [&](int v) -> int { return v + 1; };
for(int i=0; i< newV.size() ; i++)
{
std::cout << newV[i] << std::endl;
}
};
For the case of std::unordered_set you would only have to replace push_back with insert
The pipe operator here has the same well known semantics as on Unix/Linux shells and some languages
You could use std::generate and std::transform to do this.

Resources