How to store elements in set in insertion order.
for example.
set<string>myset;
myset.insert("stack");
myset.insert("overflow");
If you print, the output is
overflow
stack
needed output :
stack
overflow
One way is to use two containers, a std::deque to store the elements in insertion order, and another std::set to make sure there are no duplicates.
When inserting an element, check if it's in the set first, if yes, throw it out; if it's not there, insert it both in the deque and the set.
One common scenario is to insert all elements first, then process(no more inserting), if this is the case, the set can be freed after the insertion process.
A set is the wrong container for keeping insertion order, it will sort its element according to the sorting criterion and forget the insertion order. You have to use a sequenced container like vector, deque or list for that. If you additionally need the associative access set provides you would have to store your elements in multiple containers simultaneously or use a non-STL container like boost::multi_index which can maintain multiple element orders at the same time.
PS: If you sort the elements before inserting them in a set, the set will keep them in insertion order but I think that will not address your problem.
If you don't need any order besides the insertion order, you could also store the insert number in the stored element and make that the sorting criterion. However, why one would use a set in this case at all escapes me. ;)
Here's how I do it:
template <class T>
class VectorSet
{
public:
using iterator = typename vector<T>::iterator;
using const_iterator = typename vector<T>::const_iterator;
iterator begin() { return theVector.begin(); }
iterator end() { return theVector.end(); }
const_iterator begin() const { return theVector.begin(); }
const_iterator end() const { return theVector.end(); }
const T& front() const { return theVector.front(); }
const T& back() const { return theVector.back(); }
void insert(const T& item) { if (theSet.insert(item).second) theVector.push_back(item); }
size_t count(const T& item) const { return theSet.count(item); }
bool empty() const { return theSet.empty(); }
size_t size() const { return theSet.size(); }
private:
vector<T> theVector;
set<T> theSet;
};
Of course, new forwarding functions can be added as needed, and can be forwarded to whichever of the two data structures implements them most efficiently. If you are going to make heavy use of STL algorithms on this (I haven't needed to so far) you may also want to define member types that the STL expects to find, like value_type and so forth.
If you can use Boost, a very straightforward solution is to use the header-only library Boost.Bimap (bidirectional maps).
Consider the following sample program that will display your dummy entries in insertion order (try out here):
#include <iostream>
#include <string>
#include <type_traits>
#include <boost/bimap.hpp>
using namespace std::string_literals;
template <typename T>
void insertCallOrdered(boost::bimap<T, size_t>& mymap, const T& element) {
// We use size() as index, therefore indexing with 0, 1, ...
// as we add elements to the bimap.
mymap.insert({ element, mymap.size() });
}
int main() {
boost::bimap<std::string, size_t> mymap;
insertCallOrdered(mymap, "stack"s);
insertCallOrdered(mymap, "overflow"s);
// Iterate over right map view (integers) in sorted order
for (const auto& rit : mymap.right) {
std::cout << rit.first << " -> " << rit.second << std::endl;
}
}
I'm just wondering why nobody has suggested using such a nice library as Boost MultiIndex. Here's an example how to do that:
#include <boost/multi_index_container.hpp>
#include <boost/multi_index/indexed_by.hpp>
#include <boost/multi_index/identity.hpp>
#include <boost/multi_index/sequenced_index.hpp>
#include <boost/multi_index/ordered_index.hpp>
#include <iostream>
template<typename T>
using my_set = boost::multi_index_container<
T,
boost::multi_index::indexed_by<
boost::multi_index::sequenced<>,
boost::multi_index::ordered_unique<boost::multi_index::identity<T>>
>
>;
int main() {
my_set<int> set;
set.push_back(10);
set.push_back(20);
set.push_back(3);
set.push_back(11);
set.push_back(1);
// Prints elements of the set in order of insertion.
const auto &index = set.get<0>();
for (const auto &item : index) {
std::cout << item << " ";
}
// Prints elements of the set in order of value.
std::cout << "\n";
const auto &ordered_index = set.get<1>();
for (const auto &item : ordered_index) {
std::cout << item << " ";
}
}
what you need is this, very simple and a standard library. Example online compiler link: http://cpp.sh/7hsxo
#include <iostream>
#include <string>
#include <unordered_set>
static std::unordered_set<std::string> myset;
int main()
{
myset.insert("blah");
myset.insert("blah2");
myset.insert("blah3");
int count = 0;
for ( auto local_it = myset.begin(); local_it!= myset.end(); ++local_it ) {
printf("index: [%d]: %s\n", count, (*local_it).c_str());
count++;
}
printf("\n");
for ( unsigned i = 0; i < myset.bucket_count(); ++i) {
for ( auto local_it = myset.begin(i); local_it!= myset.end(i); ++local_it )
printf("bucket: [%d]: %s\n", i, (*local_it).c_str());
}
}
Related
Codes below doesnt' works properly, when I reference to it, it causes Member call on null pointer error, if it's not supported, why it allow the use of insert(end, {})(No compile error).
#include <vector>
#include <iostream>
using namespace std;
int main() {
vector<vector<pair<int, int>>> vv;
auto it = vv.insert(vv.end(), {});
cout << it->size() << endl;
}
When I changed {} to vector<pair<int, int>>, no error shows and print 0.
Solved by comments, It calls iterator insert( const_iterator pos, std::initializer_list<T> ilist ), So change it to insert(end, {{}}) could work.
According to cppreference – std::vector<T,Allocator>::insert(), all flavors of insert() return the iterator of first inserted element or the insertion position if nothing was inserted.
In OPs exposed MCVE:
#include <vector>
#include <iostream>
using namespace std;
int main() {
vector<vector<pair<int, int>>> vv;
auto it = vv.insert(vv.end(), {});
cout << it->size() << endl;
}
the line
auto it = vv.insert(vv.end(), {});
doesn't use the
iterator insert( const_iterator pos, const T& value );
as it might be expected but the
iterator insert( const_iterator pos, std::initializer_list<T> ilist );.
Hence, there are 0 elements inserted and the insert() returns the end() iterator which was passed.
So,
cout << it->size() << endl;
accesses the contents of end() which is Undefined Behavior.
I made a small sample to demonstrate this:
#include <initializer_list>
#include <iostream>
#include <vector>
template <typename T>
struct Container: std::vector<T> {
using typename std::vector<T>::iterator;
using typename std::vector<T>::const_iterator;
iterator insert( const_iterator pos, const T& value )
{
std::cout << "insert single value\n";
return std::vector<T>::insert(pos, value);
}
iterator insert( const_iterator pos, std::initializer_list<T> ilist )
{
std::cout << "insert initializer list\n";
return std::vector<T>::insert(pos, ilist);
}
};
using namespace std;
int main() {
Container<vector<pair<int, int>>> vv;
auto it = vv.insert(vv.end(), {});
cout << /*it->*/vv.size() << endl;
}
Output:
insert initializer list
0
Live Demo on coliru
Note:
I'm aware that it's, at least, bad style to overload std::vector.
I did this exceptionally to show the used function call (and I didn't have a better idea how to achieve this).
The line auto it = vv.insert(vv.end(), {}); is using the form iterator insert( const_iterator pos, std::initializer_list<T> ilist );.
As int the line auto it = vv.insert(vv.end(), {});, the initlizer list have no element so no element is inserted in the vector vv.
As there is no element is inserted so it is same as vv.end() for which it is invalid to deference.
You can verify it via checking the length of vv after insertion. See sample code here to check it.
I'm looking for a good data structure that can maintain its elements sorted. Currently I'm trying Boost.Heap.
I frequently need to orderly traverse the data structure and when reaching an element based on some property, update its priority. Boost.Heap priority queues provide ordered and non-ordered iterators. Element updates occurs through a node handle, a handle can be obtained from a ordinary non-ordered iterator, but not directly from a ordered one as in the following example:
#include <iostream>
#include <algorithm>
#include <boost/heap/fibonacci_heap.hpp>
using namespace boost::heap;
int main()
{
fibonacci_heap<int> fib_heap;
fib_heap.push(1);
fib_heap.push(2);
fib_heap.push(3);
for(auto i = fib_heap.ordered_begin(); i != fib_heap.ordered_end(); ++i)
{
// no viable conversion here
auto h = fibonacci_heap<int>::s_handle_from_iterator(i);
if(*h == 2) // dumb test
{
fib_heap.increase(h, *h + 2);
break;
}
}
std::for_each(fib_heap.ordered_begin(), fib_heap.ordered_end(),
[](const int &e)
{
std::cout << e << std::endl;
});
}
How can I orderly traverse the queue and update an element in the traversal?
Note that I leave traversal after the update.
(Suggestions of alternative libraries for such purpose are welcome)
If I find no better alternative, I'll need to save the handle inside each corresponding element for later usage (c++1y code):
#include <iostream>
#include <algorithm>
#include <boost/heap/fibonacci_heap.hpp>
using namespace boost::heap;
template<typename T>
struct heap_data
{
typedef typename fibonacci_heap<heap_data>::handle_type handle_t;
handle_t handle;
T data;
heap_data(const T &data_) : data(data_) {}
bool operator<(heap_data const & rhs) const
{
return data < rhs.data;
}
};
void setup_handle(fibonacci_heap<heap_data<int>>::handle_type &&handle)
{
(*handle).handle = handle;
}
int main()
{
fibonacci_heap<heap_data<int>> heap;
setup_handle(heap.emplace(1));
setup_handle(heap.emplace(2));
setup_handle(heap.emplace(3));
std::find_if(heap.ordered_begin(), heap.ordered_end(),
[&heap](const heap_data<int> &e)
{
if(e.data == 2)
{
const_cast<heap_data<int> &>(e).data += 2;
heap.increase(e.handle);
return true;
}
return false;
});
std::for_each(heap.ordered_begin(), heap.ordered_end(),
[](const heap_data<int> &e)
{
std::cout << e.data << std::endl;
});
}
Your requirements are not very clear to me. But how about std::multimap or std::multiset? Update operations are O(log n). I think traversal should be O(n) (BST traversal), but it's not documented in my standard C++ references (cppreference.com, cplusplus.com). Looks like boost::heap traversal is amortized O(n log n).
Python's itertools has tee for n-plicating iterables:
def tee(iterable, n=2):
it = iter(iterable)
deques = [collections.deque() for i in range(n)]
def gen(mydeque):
while True:
if not mydeque: # when the local deque is empty
newval = next(it) # fetch a new value and
for d in deques: # load it to all the deques
d.append(newval)
yield mydeque.popleft()
return tuple(gen(d) for d in deques)
I couldn't find the equivalent in Boost::Range. Am I missing something or should I just roll my own?
itertools.tee is well-suited for single pass iterables which are ubiquitous in Python. For instance Generators are single pass, and they are often used.
But if you already have list/deque you will not use itertools.tee for it, because it would involve superfluous duplication - you can just iterate over original list/deque over and over again.
C++ also has concept of single pass ranges, for instance Input Iterator, but they are not so ubiquitous. It is consequence of another set of aims of typical C++ program - give to user maximum as possible maintaining best performance. It is another mindset if you wish.
To illustrate this let's compare boost::transformed and itertools.imap (or generator expressions):
They both provide view of input sequence via given "prism". itertools.imap returns single pass iterable, while boost::transformed returns range view which has same category as input range - i.e., if you would pass Random Access Range as input you would get Random Access Range as the result.
Another fact is that C++ employs value semantics by default, while python has pointer semantics. It means that if copy iterator in C++, and "bump" it several times - original iterator will not be changed (though it can be invalidated if it is single pass range, but it is not the point).
But, sometimes you do want to accumulate values from single pass range and look at them several times. In such case, most common solution is to accumulate values to some container explicitly, by hands. For instance:
vector<int> cache(first,last);
However, tee-like wrappers are still possible in C++, here is proof-of-concept. Usage is:
auto forward_range = tee_range(first,last);
tee_range takes single pass range as argument and returns forward range (which is multi-pass) (there is also make_tee_iterator, which works at iterator level). So, you can take copies of that range and iterate it several times:
auto r = forward_range;
auto out = ostream_iterator<int>(cout," ");
copy(forward_range,out);
copy(forward_range,out);
copy(r,out);
Therer is also improvenment over itertools.tee - internally, only one deque is used to cache values.
live demo:
#include <boost/range/adaptor/transformed.hpp>
#include <boost/iterator/iterator_facade.hpp>
#include <boost/smart_ptr/make_shared.hpp>
#include <boost/range/iterator_range.hpp>
#include <boost/smart_ptr/shared_ptr.hpp>
#include <boost/container/vector.hpp>
#include <boost/container/deque.hpp>
#include <boost/range/algorithm.hpp>
#include <algorithm>
#include <iterator>
#include <cassert>
#include <limits>
template<typename InputIterator>
class tee_iterator : public boost::iterator_facade
<
tee_iterator<InputIterator>,
const typename std::iterator_traits<InputIterator>::value_type,
boost::forward_traversal_tag
>
{
typedef typename std::iterator_traits<InputIterator>::value_type Value;
typedef unsigned Index;
struct Data
{
boost::container::deque<Value> values;
boost::container::vector<tee_iterator*> iterators;
InputIterator current,end;
Index min_index, current_index;
Index poped_from_front;
//
Data(InputIterator first,InputIterator last)
: current(first), end(last), min_index(0), current_index(0), poped_from_front(0)
{}
~Data()
{
assert(iterators.empty());
}
};
boost::shared_ptr<Data> shared_data;
Index index;
static Index get_index(tee_iterator *p)
{
return p->index;
}
public:
tee_iterator()
: index(std::numeric_limits<Index>::max())
{}
tee_iterator(InputIterator first,InputIterator last)
: shared_data(boost::make_shared<Data>(first,last)), index(0)
{
shared_data->iterators.push_back(this);
}
tee_iterator(const tee_iterator &x)
: shared_data(x.shared_data), index(x.index)
{
if(shared_data)
shared_data->iterators.push_back(this);
}
friend void swap(tee_iterator &l,tee_iterator &r)
{
using std::swap;
*boost::find(l.shared_data->iterators,&l) = &r;
*boost::find(r.shared_data->iterators,&r) = &l;
swap(l.shared_data,r.shared_data);
swap(l.index,r.index);
}
tee_iterator &operator=(tee_iterator x)
{
swap(x,*this);
}
~tee_iterator()
{
if(shared_data)
{
erase_from_iterators();
if(!shared_data->iterators.empty())
{
using boost::adaptors::transformed;
shared_data->min_index = *boost::min_element(shared_data->iterators | transformed(&get_index));
Index to_pop = shared_data->min_index - shared_data->poped_from_front;
if(to_pop>0)
{
shared_data->values.erase(shared_data->values.begin(), shared_data->values.begin()+to_pop);
shared_data->poped_from_front += to_pop;
}
}
}
}
private:
friend class boost::iterator_core_access;
void erase_from_iterators()
{
shared_data->iterators.erase(boost::find(shared_data->iterators,this));
}
bool last_min_index() const
{
return boost::count
(
shared_data->iterators | boost::adaptors::transformed(&get_index),
shared_data->min_index
)==1;
}
Index obtained() const
{
return Index(shared_data->poped_from_front + shared_data->values.size());
}
void increment()
{
if((shared_data->min_index == index) && last_min_index())
{
shared_data->values.pop_front();
++shared_data->min_index;
++shared_data->poped_from_front;
}
++index;
if(obtained() <= index)
{
++shared_data->current;
if(shared_data->current != shared_data->end)
{
shared_data->values.push_back(*shared_data->current);
}
else
{
erase_from_iterators();
index=std::numeric_limits<Index>::max();
shared_data.reset();
}
}
}
bool equal(const tee_iterator& other) const
{
return (shared_data.get()==other.shared_data.get()) && (index == other.index);
}
const Value &dereference() const
{
if((index==0) && (obtained() <= index))
{
shared_data->values.push_back(*(shared_data->current));
}
assert( (index-shared_data->poped_from_front) < shared_data->values.size());
return shared_data->values[index-shared_data->poped_from_front];
}
};
template<typename InputIterator>
tee_iterator<InputIterator> make_tee_iterator(InputIterator first,InputIterator last)
{
return tee_iterator<InputIterator>(first,last);
}
template<typename InputIterator>
boost::iterator_range< tee_iterator<InputIterator> > tee_range(InputIterator first,InputIterator last)
{
return boost::iterator_range< tee_iterator<InputIterator> >
(
tee_iterator<InputIterator>(first,last),
tee_iterator<InputIterator>()
);
}
// _______________________________________________________ //
#include <iostream>
#include <ostream>
#include <sstream>
int main()
{
using namespace std;
stringstream ss;
ss << "1 2 3 4 5";
istream_iterator<int> first(ss /*cin*/ ),last;
typedef boost::iterator_range< tee_iterator< istream_iterator<int> > > Range; // C++98
Range r1 = tee_range(first,last);
Range r2 = r1, r3 = r1;
boost::copy(r1,ostream_iterator<int>(cout," "));
cout << endl;
boost::copy(r2,ostream_iterator<int>(cout," "));
cout << endl;
boost::copy(r2,ostream_iterator<int>(cout," "));
}
Output is:
1 2 3 4 5
1 2 3 4 5
1 2 3 4 5
Boost.Spirit has Multi Pass iterator which has similar aims.
The multi_pass iterator will convert any input iterator into a forward iterator suitable for use with Spirit.Qi. multi_pass will buffer data when needed and will discard the buffer when its contents is not needed anymore. This happens either if only one copy of the iterator exists or if no backtracking can occur.
basically, I have the
map<std::string, int>
so if i have
foo 5
bar 10
jack 3
in the map, I want to display it (notice the reverse order)
bar 10
foo 5
jack 3
And every time it is updated, I want iterate through all the elements, cout them, sorted by value. What is the good way to implement that? should I provide a comparator to the constructor?
I want to note that values in the map will be updated at least 100 million times, so efficiency is crucial, where as extra-space is no problem
Please no Boost solutions...thx
struct keyval_t { std::string key; int val; };
int operator<(const keyval_t &a, const ketval_t &b)
{ return a.val<b.val || (a.val==b.val && a.key<b.key); }
Then you need one map and one set:
map<std::string, int>; set<keyval_t>;
On update, you need to look up the map first to determine the key-value pair and then update both map and set. On printing, you just iterate through the set. In terms of theoretical time complexity, this is optimal. It doubles the memory, though. Does this meet your goal?
To reduce memory, you may consider the following:
map<std::string,uint64_t>; set<uint64_t>;
The value of the map (also the key of the set) is: (uint64_t)val<<32|counter, where counter is something that differentiates identical values. For example, whenever you insert a key, increase the counter by 1. You do not need to update the counter when you update the value. If you do not like uint64_t, use pair<int,int> instead. This solution is also faster as it avoids comparisons between strings.
If you want a performant map sorted by both key and value, you want Boost MultiIndex, it gets updated (resorted) on every update (which you have to do manually) and has a good documentation.
The previous responses have the inconvenience not to take into account the initial requirements (the key is std::string and the value is int).
EDITED: following the comments, I suppose presenting it directly with a Bimap is better :)
So here we go, right in!
#include <boost/bimap.hpp>
class MyMap
{
struct name {};
struct value {};
typedef boost::tagged<name, std::string> tagged_name;
typedef boost::tagged<value, int> tagged_value;
// unordered_set_of: guarantees only unicity (not order)
// multi_set_of: guarantees only order (not unicity)
typedef boost::bimap< boost::unordered_set_of< tagged_name >,
boost::multi_set_of< tagged_value,
std::greater< tagged_value >
>
> impl_type;
public:
// Redefine all usual types here
typedef typename impl_type::map_by<name>::const_iterator const_iterator;
typedef typename impl_type::value_type value_type;
// Define the functions you want
// the bimap will not allow mutators because the elements are used as keys
// so you may want to add wrappers
std::pair< iterator, bool > insert(const value_type & x)
{
std::pair< iterator, bool > result = m_impl.insert(x);
if (result.second) this->display();
return result;
} // insert
iterator insert(iterator position, const value_type & x)
{
iterator result = m_impl.insert(x);
this->display();
return result;
} // insert
template< class InputIterator >
void insert(InputIterator first, InputIterator last)
{
m_impl.insert(first, last);
this->display();
} // insert
private:
void display() const
{
// Yeah I know about std::for_each...
typedef typename impl_type::map_by<value>::const_iterator const_it;
for (const_it it = m_impl.begin(), end = m_impl.end(); it != end; ++it)
{
// Note the inversion of the 'second' and 'first',
// we are looking at it from the right
std::cout << it->second << " " << it->first << std::endl;
}
}
impl_type m_impl;
}; // class MyMap
Here you go.
I strongly suggest that you consult the bimap documentation though. There are a lot of possibilities for storing (set_of, unordered_set_of, unconstrained_set_of, the muli variants, the list_of variant...) so there is probably one that could do what you want.
Then you also have the possibility to just sort each time you display:
#include <set>
#include <map>
// Just use a simple std::map<std::string,int> for your impl_type
// Mutators are allowed since the elements are sorted each time you display
struct Comparator
{
bool operator(const value_type& lhs, const value_type& rhs) const
{
return lhs.second < rhs.value;
}
};
void display() const
{
typedef std::multi_set<value_type, Comparator> sort_type;
sort_type mySet;
std::copy(m_impl.begin(), m_impl.end(), std::inserter(mySet, mySet.end()));
for (sort_type it = mySet.begin(), end = mySet.end(); it != end; ++it)
{
std::cout << it->first<< " " << it->second << std::endl;
}
}
It should be easier to understand my point now :)
Well, you have to sort by key. The easiest way to "sort by value" is to use a multimap with the key and value switched. So here's a way to do that (note -- i don't have access to a compiler right now, so if it doesn't compile, I'm sorry):
#include <algorithm>
#include <functional>
#include <map>
#include <string>
#include <utility>
typedef std::multimap<int, std::string, std::greater<int> > MapType;
struct MapKeyOutput
{
void operator()(const MapType::value_type& val)
{
std::cout << val.second << " " << val.first << "\n";
}
}
void display_insert(MapType& m, const std::string& str, int val)
{
m.insert(std::make_pair(val, str));
std::for_each(m.begin(), m.end(), MapKeyOutput());
}
int main()
{
MapType m;
display_insert(m, "Billy", 5);
display_insert(m, "Johnny", 10);
}
You could also make a map class that uses a multimap internally, I just didn't want to type it out. Then display_insert would be some member function instead. This should demonstrate the point, though. Points of interest:
typedef std::multimap<int, std::string, std::greater<int> > MapType;
Note the comparator is greater<int> to sort descending. We're using a multimap so more than one name can have the same number.
struct MapKeyOutput
{
void operator()(const MapType::value_type& val)
{
std::cout << val.second << " " << val.first << "\n";
}
}
This is a function object to output one element in the map. second is output before first so the order is what you want.
std::for_each(m.begin(), m.end(), MapKeyOutput());
This applies our function object to every element in m.
All I want to do is to check whether an element exists in the vector or not, so I can deal with each case.
if ( item_present )
do_this();
else
do_that();
You can use std::find from <algorithm>:
#include <algorithm>
#include <vector>
vector<int> vec;
//can have other data types instead of int but must same datatype as item
std::find(vec.begin(), vec.end(), item) != vec.end()
This returns an iterator to the first element found. If not present, it returns an iterator to one-past-the-end. With your example:
#include <algorithm>
#include <vector>
if ( std::find(vec.begin(), vec.end(), item) != vec.end() )
do_this();
else
do_that();
As others have said, use the STL find or find_if functions. But if you are searching in very large vectors and this impacts performance, you may want to sort your vector and then use the binary_search, lower_bound, or upper_bound algorithms.
If your vector is not ordered, use the approach MSN suggested:
if(std::find(vector.begin(), vector.end(), item)!=vector.end()){
// Found the item
}
If your vector is ordered, use binary_search method Brian Neal suggested:
if(binary_search(vector.begin(), vector.end(), item)){
// Found the item
}
binary search yields O(log n) worst-case performance, which is way more efficient than the first approach. In order to use binary search, you may use qsort to sort the vector first to guarantee it is ordered.
Use find from the algorithm header of stl.I've illustrated its use with int type. You can use any type you like as long as you can compare for equality (overload == if you need to for your custom class).
#include <algorithm>
#include <vector>
using namespace std;
int main()
{
typedef vector<int> IntContainer;
typedef IntContainer::iterator IntIterator;
IntContainer vw;
//...
// find 5
IntIterator i = find(vw.begin(), vw.end(), 5);
if (i != vw.end()) {
// found it
} else {
// doesn't exist
}
return 0;
}
In C++11 you can use any_of. For example if it is a vector<string> v; then:
if (any_of(v.begin(), v.end(), bind(equal_to<string>(), _1, item)))
do_this();
else
do_that();
Alternatively, use a lambda:
if (any_of(v.begin(), v.end(), [&](const std::string& elem) { return elem == item; }))
do_this();
else
do_that();
I use something like this...
#include <algorithm>
template <typename T>
const bool Contains( std::vector<T>& Vec, const T& Element )
{
if (std::find(Vec.begin(), Vec.end(), Element) != Vec.end())
return true;
return false;
}
if (Contains(vector,item))
blah
else
blah
...as that way it's actually clear and readable.
(Obviously you can reuse the template in multiple places).
Here's a function that will work for any Container:
template <class Container>
const bool contains(const Container& container, const typename Container::value_type& element)
{
return std::find(container.begin(), container.end(), element) != container.end();
}
Note that you can get away with 1 template parameter because you can extract the value_type from the Container. You need the typename because Container::value_type is a dependent name.
Bear in mind that, if you're going to be doing a lot of lookups, there are STL containers that are better for that. I don't know what your application is, but associative containers like std::map may be worth considering.
std::vector is the container of choice unless you have a reason for another, and lookups by value can be such a reason.
Use the STL find function.
Keep in mind that there is also a find_if function, which you can use if your search is more complex, i.e. if you're not just looking for an element, but, for example, want see if there is an element that fulfills a certain condition, for example, a string that starts with "abc". (find_if would give you an iterator that points to the first such element).
With boost you can use any_of_equal:
#include <boost/algorithm/cxx11/any_of.hpp>
bool item_present = boost::algorithm::any_of_equal(vector, element);
You can try this code:
#include <algorithm>
#include <vector>
// You can use class, struct or primitive data type for Item
struct Item {
//Some fields
};
typedef std::vector<Item> ItemVector;
typedef ItemVector::iterator ItemIterator;
//...
ItemVector vtItem;
//... (init data for vtItem)
Item itemToFind;
//...
ItemIterator itemItr;
itemItr = std::find(vtItem.begin(), vtItem.end(), itemToFind);
if (itemItr != vtItem.end()) {
// Item found
// doThis()
}
else {
// Item not found
// doThat()
}
From C++20, using ranges (#include <ranges>)
//SAMPLE DATA
std::vector<int> vecOfElements = { 2,4,6,8 };
//DO SOMETHING IF 8 IN VECTOR
if (std::ranges::find(vecOfElements, 8) != vecOfElements.end())
{
std::cout << "DO SOMETHING" << std::endl;
}
You can use the find function, found in the std namespace, ie std::find. You pass the std::find function the begin and end iterator from the vector you want to search, along with the element you're looking for and compare the resulting iterator to the end of the vector to see if they match or not.
std::find(vector.begin(), vector.end(), item) != vector.end()
You're also able to dereference that iterator and use it as normal, like any other iterator.
You can use count too.
It will return the number of items present in a vector.
int t=count(vec.begin(),vec.end(),item);
template <typename T> bool IsInVector(const T & what, const std::vector<T> & vec)
{
return std::find(vec.begin(),vec.end(),what)!=vec.end();
}
I've personally used templates of late to handle multiple types of containers at once rather than deal only with vectors. I found a similar example online (can't remember where) so credit goes to whoever I've pilfered this from. This particular pattern seems to handle raw arrays as well.
template <typename Container, typename T = typename std::decay<decltype(*std::begin(std::declval<Container>()))>::type>
bool contains(Container && c, T v)
{
return std::find(std::begin(c), std::end(c), v) != std::end(c);
}
(C++17 and above):
can use std::search also
This is also useful for searching sequence of elements.
#include <algorithm>
#include <iostream>
#include <vector>
template <typename Container>
bool search_vector(const Container& vec, const Container& searchvec)
{
return std::search(vec.begin(), vec.end(), searchvec.begin(), searchvec.end()) != vec.end();
}
int main()
{
std::vector<int> v = {2,4,6,8};
//THIS WORKS. SEARCHING ONLY ONE ELEMENT.
std::vector<int> searchVector1 = {2};
if(search_vector(v,searchVector1))
std::cout<<"searchVector1 found"<<std::endl;
else
std::cout<<"searchVector1 not found"<<std::endl;
//THIS WORKS, AS THE ELEMENTS ARE SEQUENTIAL.
std::vector<int> searchVector2 = {6,8};
if(search_vector(v,searchVector2))
std::cout<<"searchVector2 found"<<std::endl;
else
std::cout<<"searchVector2 not found"<<std::endl;
//THIS WILL NOT WORK, AS THE ELEMENTS ARE NOT SEQUENTIAL.
std::vector<int> searchVector3 = {8,6};
if(search_vector(v,searchVector3))
std::cout<<"searchVector3 found"<<std::endl;
else
std::cout<<"searchVector3 not found"<<std::endl;
}
Also there is flexibility of passing some search algorithms. Refer here.
https://en.cppreference.com/w/cpp/algorithm/search
If you wanna find a string in a vector:
struct isEqual
{
isEqual(const std::string& s): m_s(s)
{}
bool operator()(OIDV* l)
{
return l->oid == m_s;
}
std::string m_s;
};
struct OIDV
{
string oid;
//else
};
VecOidv::iterator itFind = find_if(vecOidv.begin(), vecOidv.end(), isEqual(szTmp));