Template to check if vector and map contains value - c++

I'm a beginner in c++ i was searching for templates that could check if a vector / map independent of their data type, contains a given value, I have found these:
template <typename Container, typename Value>
bool vector_contains(const Container& c, const Value& v)
{
return std::find(std::begin(c), std::end(c), v) != std::begin(c);
}
template< typename container, typename key >
auto map_contains(container const& c, key const& k)
-> decltype(c.find(k) != c.end())
{
return c.find(k) != c.end();
}
My doubt is, does using templates to do this kind of verification impact performance somehow?

I have found these
Ok, but do analyze them. They are sub optimal and/or plain wrong.
template <typename Container, typename Value>
bool vector_contains(const Container& c, const Value& v)
{
return std::find(std::begin(c), std::end(c), v) != std::begin(c);
}
This will return true as long as v is not the first value found. It'll also return true if v is not found at all.
A vector, without any other information, is unsorted, which means that contains will have to search from the first element to the last if the value is not found. Such searches are considered expensive.
If you on the other hand std::sort the vector and use the same Comparator when using std::binary_search, it'll have a quicker lookup. Sorting takes time too, though.
template< typename container, typename key >
auto map_contains(container const& c, key const& k) -> decltype(c.find(k) != c.end())
{
return c.find(k) != c.end();
}
This looks like it may work for types matching the function template. It should use map::contains instead - if it's meant to be used with maps.

Related

What is the C++ equivalent of Python's "in" operator?

What is the C++ way of checking if an element is contained in an array/list, similar to what the in operator does in Python?
if x in arr:
print "found"
else
print "not found"
How does the time complexity of the C++ equivalent compare to Python's in operator?
The time complexity of Python's in operator varies depending on the data structure it is actually called with. When you use it with a list, complexity is linear (as one would expect from an unsorted array without an index). When you use it to look up set membership or presence of a dictionary key complexity is constant on average (as one would expect from a hash table based implementation):
https://wiki.python.org/moin/TimeComplexity
In C++ you can use std::find to determine whether or not an item is contained in a std::vector. Complexity is said to be linear (as one would expect from an unsorted array without an index). If you make sure the vector is sorted, you can also use std::binary_search to achieve the same in logarithmic time.
http://en.cppreference.com/w/cpp/algorithm/find
Check if element is in the list (contains)
Check if element found in array c++
http://en.cppreference.com/w/cpp/algorithm/binary_search
The associative containers provided by the standard library (std::set, std::unordered_set, std::map, ...) provide the member functions find() and count() and contains() (C++20) for this. These will perform better than linear search, i.e., logarithmic or constant time depending on whether you have picked the ordered or the unordered alternative. Which one of these functions to prefer largely depends on what you want to achieve with that info afterwards, but also a bit on personal preference. (Lookup the documentation for details and examples.)
How to check that an element is in a std::set?
How to check if std::map contains a key without doing insert?
https://en.wikipedia.org/wiki/Associative_containers
http://en.cppreference.com/w/cpp/container
If you want to, you can use some template magic to write a wrapper function that picks the correct method for the container at hand, e.g., as presented in this answer.
You can approach this in two ways:
You can use std::find from <algorithm>:
auto it = std::find(container.begin(), container.end(), value);
if (it != container.end())
return it;
or you can iterate through every element in your containers with for ranged loops:
for(const auto& it : container)
{
if(it == value)
return it;
}
Python does different things for in depending on what kind of container it is. In C++, you'd want the same mechanism. Rule of thumb for the standard containers is that if they provide a find(), it's going to be a better algorithm than std::find() (e.g. find() for std::unordered_map is O(1), but std::find() is always O(N)).
So we can write something to do that check ourselves. The most concise would be to take advantage of C++17's if constexpr and use something like Yakk's can_apply:
template <class C, class K>
using find_t = decltype(std::declval<C const&>().find(std::declval<K const&>()));
template <class Container, class Key>
bool in(Container const& c, Key const& key) {
if constexpr (can_apply<find_t, Container, Key>{}) {
// the specialized case
return c.find(key) != c.end();
} else {
// the general case
using std::begin; using std::end;
return std::find(begin(c), end(c), key) != end(c);
}
}
In C++11, we can take advantage of expression SFINAE:
namespace details {
// the specialized case
template <class C, class K>
auto in_impl(C const& c, K const& key, int )
-> decltype(c.find(key), true) {
return c.find(key) != c.end();
}
// the general case
template <class C, class K>
bool in_impl(C const& c, K const& key, ...) {
using std::begin; using std::end;
return std::find(begin(c), end(c), key) != end(c);
}
}
template <class Container, class Key>
bool in(Container const& c, Key const& key) {
return details::in_impl(c, key, 0);
}
Note that in both cases we have the using std::begin; using std::end; two-step in order to handle all the standard containers, raw arrays, and any use-provided/adapted containers.
This gives you an infix *in* operator:
namespace notstd {
namespace ca_helper {
template<template<class...>class, class, class...>
struct can_apply:std::false_type{};
template<class...>struct voider{using type=void;};
template<class...Ts>using void_t=typename voider<Ts...>::type;
template<template<class...>class Z, class...Ts>
struct can_apply<Z,void_t<Z<Ts...>>, Ts...>:std::true_type{};
}
template<template<class...>class Z, class...Ts>
using can_apply = ca_helper::can_apply<Z,void,Ts...>;
namespace find_helper {
template<class C, class T>
using dot_find_r = decltype(std::declval<C>().find(std::declval<T>()));
template<class C, class T>
using can_dot_find = can_apply< dot_find_r, C, T >;
template<class C, class T>
constexpr std::enable_if_t<can_dot_find<C&, T>{},bool>
find( C&& c, T&& t ) {
using std::end;
return c.find(std::forward<T>(t)) != end(c);
}
template<class C, class T>
constexpr std::enable_if_t<!can_dot_find<C&, T>{},bool>
find( C&& c, T&& t ) {
using std::begin; using std::end;
return std::find(begin(c), end(c), std::forward<T>(t)) != end(c);
}
template<class C, class T>
constexpr bool finder( C&& c, T&& t ) {
return find( std::forward<C>(c), std::forward<T>(t) );
}
}
template<class C, class T>
constexpr bool find( C&& c, T&& t ) {
return find_helper::finder( std::forward<C>(c), std::forward<T>(t) );
}
struct finder_t {
template<class C, class T>
constexpr bool operator()(C&& c, T&& t)const {
return find( std::forward<C>(c), std::forward<T>(t) );
}
constexpr finder_t() {}
};
constexpr finder_t finder{};
namespace named_operator {
template<class D>struct make_operator{make_operator(){}};
template<class T, char, class O> struct half_apply { T&& lhs; };
template<class Lhs, class Op>
half_apply<Lhs, '*', Op> operator*( Lhs&& lhs, make_operator<Op> ) {
return {std::forward<Lhs>(lhs)};
}
template<class Lhs, class Op, class Rhs>
auto operator*( half_apply<Lhs, '*', Op>&& lhs, Rhs&& rhs )
-> decltype( named_invoke( std::forward<Lhs>(lhs.lhs), Op{}, std::forward<Rhs>(rhs) ) )
{
return named_invoke( std::forward<Lhs>(lhs.lhs), Op{}, std::forward<Rhs>(rhs) );
}
}
namespace in_helper {
struct in_t:notstd::named_operator::make_operator<in_t> {};
template<class T, class C>
bool named_invoke( T&& t, in_t, C&& c ) {
return ::notstd::find(std::forward<C>(c), std::forward<T>(t));
}
}
in_helper::in_t in;
}
On a flat container, like a vector array or string, it is O(n).
On an associative sorted container, like a std::map, std::set, it is O(lg(n)).
On an unordered associated container, like std::unordered_set, it is O(1).
Test code:
std::vector<int> v{1,2,3};
if (1 *in* v)
std::cout << "yes\n";
if (7 *in* v)
std::cout << "no\n";
std::map<std::string, std::string, std::less<>> m{
{"hello", "world"}
};
if ("hello" *in* m)
std::cout << "hello world\n";
Live example.
C++14, but mainly for enable_if_t.
So what is going on here?
Well, can_apply is a bit of code that lets me write can_dot_find, which detects (at compile time) if container.find(x) is a valid expression.
This lets me dispatch the searching code to use member-find if it exists. If it doesn't exist, a linear search using std::find is used instead.
Which is a bit of a lie. If you define a free function find(c, t) in the namespace of your container, it will use that rather than either of the above. But that is me being fancy (and it lets you extend 3rd party containers with *in* support).
That ADL (argument dependent lookup) extensibity (the 3rd party extension ability) is why we have three different functions named find, two in a helper namespace and one in notstd. You are intended to call notstd::find.
Next, we want a python-like in, and what is more python like than an infix operator? To do this in C++ you need to wrap your operator name in other operators. I chose *, so we get an infix *in* named operator.
TL;DR
You do using notstd::in; to import the named operator in.
After that, t *in* c first checks if find(t,c) is valid. If not, it checks if c.find(t) is valid. If that fails, it does a linear search of c using std::begin std::end and std::find.
This gives you very good performance on a wide variety of std containers.
The only thing it doesn't support is
if (7 *in* {1,2,3})
as operators (other than =) cannot deduce initializer lists I believe. You could get
if (7 *in* il(1,2,3))
to work.
I guess one might make use of this thread and create a custom version of in function.
The main idea is to use SFINAE (Substitution Failure Is Not An Error) to differentiate associative containers (which have key_type member) from sequence containers (which have no key_type member).
Here is a possible implementation:
namespace detail
{
template<typename, typename = void>
struct is_associative : std::false_type {};
template<typename T>
struct is_associative<T,
std::enable_if_t<sizeof(typename T::key_type) != 0>> : std::true_type {};
template<typename C, typename T>
auto in(const C& container, const T& value) ->
std::enable_if_t<is_associative<C>::value, bool>
{
using std::cend;
return container.find(value) != cend(container);
}
template<typename C, typename T>
auto in(const C& container, const T& value) ->
std::enable_if_t<!is_associative<C>::value, bool>
{
using std::cbegin;
using std::cend;
return std::find(cbegin(container), cend(container), value) != cend(container);
}
}
template<typename C, typename T>
auto in(const C& container, const T& value)
{
return detail::in(container, value);
}
Small usage example on WANDBOX.
You can use std::find from <algorithm>, but this works only for datatypes like: std::map and std::vector (etc).
Also note that this will return, iterator to the first element that is found equal to the value you pass, unlike the in operator in Python that returns a bool.
I think one of the nice features of the "in" operator in python is that it can be used with different data types (strings v/s strings, numbers v/s lists, etc).
I am developing a library for using python constructions in C++. It includes "in" and "not_in" operators.
It is based on the same technique used to implement the in operator posted in a previous answer, in which make_operator<in_t> is implemented. However, it is extended for handling more cases:
Searching a string inside a string
Searching an element inside vector and maps
It works by defining several overloads for a function: bool in__(T1 &v1, T2 &v2), in which T1 and T2 consider different possible types of objects. Also, overloads for a function: bool not_in__(T1 &v1, T2 &v2) are defined. Then, the operators "in" and "not_in" call those functions for working.
The implementation is in this repository:
https://github.com/ploncomi/python_like_cpp

Making a template work with both std::map and std::unordered_map

I have the following template function that returns a copy of the given map with swapped keys and values:
template<typename M>
auto swapKeysAndValues(const M& m) {
std::map<typename M::mapped_type, typename M::key_type> swapped;
for (auto& p : m) {
swapped.emplace(p.second, p.first);
}
return swapped;
}
Is there a way of making the above template work for both std::map and std::unordered_map? That is, for std::map<K, V>, it should return std::map<V, K>, and for std::unordered_map<K, V>, it should return std::unordered_map<V, K>.
template<template <typename...> class Map, typename K, typename V>
auto swapKeyValues(const Map<K, V>& map)
{
Map<V, K> result;
for (const auto& p : map) result.emplace(p.second, p.first);
return result;
}
Live example
There are a couple of answers here so I'm not going to cover old ground.
There is however an aspect of this that you ought to consider carefully.
unordered maps are not the same as maps - they have the requirement that a hash function exists for the key (in addition to the equality predicate). As we have seen, it's trivial to write a template function that assumes the defaults, but is that what you want?
If both your K and V have hash functions available, then they are already keys. In that case, isn't what you really wanted a boost::bimap or boost::multi_index_map?

Get all vector elements that don't belong to another vector

In C# if I want to get all elements in a List List1, which don't belong to another List List2 I can do
var result List1.Except(List2);
Is there something equivalent for std::vectors in C++? (C++11 is allowed)
The following populates List3 with the content from List1 that is not in List2. I hope it is what you're looking for:
std::vector<Type> List1, List2;
//
// populate List1 and List2
//
std::vector<Type> List3;
std::copy_if(List1.begin(), List1.end(), std::back_inserter(List3),
[&List2](const Type& arg)
{ return (std::find(List2.begin(), List2.end(), arg) == List2.end());});
Alternatively, this is likely better performing, since you don't have to search the entire list to determine lack of existence. Rather you can get an early "hit" and just move to the next node. Note the logic flip in the predicate:
std::vector<Type> List3;
std::remove_copy_if(List1.begin(), List1.end(), std::back_inserter(List3),
[&List2](const Type& arg)
{ return (std::find(List2.begin(), List2.end(), arg) != List2.end());});
You need to write your own function something like this:
for (auto element : List1)
{
auto it = std::find(List2.begin(), List2.end(), element);
if(it == List2.end())
{
result.push_back(element);
}
}
You should consider if a std::list is the right data structure for that, as it is - at least in C++ - not sorted by default, so in the worst case you will have to iterate size(list2) times through all elements of the list1, using an algorithm like Asha pointed out.
A better approach would be the use of an ordered container, e.g. multiset and use std::set_difference to create a result.
For any arbitrary container you can always use the std::remove_if + container::erase combination:
template <typename Cont, typename FwdIt>
void subtract(Cont& cont, FwdIt first, FwdIt last) {
using std::begin; using std::end;
using const_reference = typename Cont::value_type const&;
cont.erase(std::remove_if(begin(cont), end(cont),
[first, last](const_reference value){
return last != std::find(first, last, value);
}), end(cont));
}
template <typename Cont1, typename Cont2>
void subtract(Cont1& cont1, Cont2 const& cont2) {
using std::begin; using std::end;
subtract(cont1, begin(cont2), end(cont2));
}
In the case of std::list you can overload the subtract function, because std::list has a dedicated remove_if member function:
template <typename T, typename Alloc, typename FwdIt>
void subtract(std::list<T, Alloc>& l, FwdIt first, FwdIt last) {
l.remove_if([first, last](T const& value){
return last != std::find(first, last, value);
});
}
template <typename T, typename Alloc, typename Cont>
void subtract(std::list<T, Alloc>& l, Cont const& cont) {
using std::begin; using std::end;
subtract(l, begin(cont), end(cont));
}
These implementation are generic and make no assumption about the sorting of the sequences.
If only your second container is guaranteed to be sorted, you can use std::binary_seach instead of find.
If both sequences are sorted, you should use std::set_difference.

A reduce function (for many set unions) in C++

What I am trying to do:
I have a simple set union function in C++ using STL, and I'm trying to wrap it in a function that will let me perform the union of arbitrarily many sets contained in STL data structures (e.g. std::list, std::vector, std::forward_list, ...).
How I tried to do it:
To start, my simple set union:
#include <algorithm>
template <typename set_type>
set_type sunion(const set_type & lhs, const set_type & rhs)
{
set_type result;
std::set_union( lhs.begin(), lhs.end(), rhs.begin(), rhs.end(), std::inserter(result, result.end()) );
return result;
}
where set_type defines some STL std::set<T>, e.g. std::set<int>.
After noticing several times that I end up needing to perform several unions on iterators of sets (in Python this would be a reduce of my sunion function over some iterable object of set_types). For instance, I might have
std::vector<std::set<int> > all_sets;
or
std::list<std::set<int> > all_sets;
etc., and I want to get the union of all sets in all_sets. I am trying to implement a simple reduce for this, which essentially does a (faster, more elegant, non-copying) version of:
sunion(... sunion( sunion( all_sets.begin(), all_sets.begin()+1 ), all_sets.begin()+2 ) , ... )
Essentially, to do this quickly, I just want to declare a set_type result and then iterate through all_sets and insert value in every set in all_sets into the result object:
template <typename set_type>
set_type sunion_over_iterator_range(const std::iterator<std::forward_iterator_tag, set_type> & begin, const std::iterator<std::forward_iterator_tag, set_type> & end)
{
set_type result;
for (std::iterator<std::forward_iterator_tag, set_type> iter = begin; iter != end; iter++)
{
insert_all(result, *iter);
}
return result;
}
where insert_all is defined:
// |= operator; faster than making a copy and performing union
template <typename set_type>
void insert_all(set_type & lhs, const set_type & rhs)
{
for (typename set_type::iterator iter = rhs.begin(); iter != rhs.end(); iter++)
{
lhs.insert(*iter);
}
}
How it didn't work:
Unfortunately, my sunion_over_iterator_range(...) doesn't work with arguments std::vector<set_type>::begin(), std::vector<set_type>::end(), which are of type std::vector<set_type>::iterator. I thought std::vector<T>::iterator returns an iterator<random_access_iterator_tag, T>. A
After compilation failed because of type incompatibility of the iterators, I looked at the stl vector source (located in /usr/include/c++/4.6/bits/stl_vector.h for g++ 4.6 & Ubuntu 11.10), and was surprised to see the typedef for vector<T>::iterator to be typedef __gnu_cxx::__normal_iterator<pointer, vector> iterator;. I had thought that a ForwardIterator was a subtype of RandomAccessIterator, and so should be fine, but clearly I was incorrect, or I would not be here.
How I am grateful and ashamed of inciting your frustration due to my inexperience:
Apologies if I'm showing my ignorance-- I am trying to learn to be a better object oriented programmer (in the past I have simply hacked everything out in C-style code).
I'm doing my best, coach! Please help me out and spare the world from bad code that I would produce without your code ninja insight...
Here's a very naive approach:
std::set<T> result;
std::vector<std::set<T>> all_sets;
for (std::set<T> & s : all_sets)
{
result.insert(std::make_move_iterator(s.begin()),
std::make_move_iterator(s.end()));
}
This invalidates the elements in the source sets, though it doesn't actually move the element nodes over. If you want to leave the source sets intact, just remove the make_move_iterator.
Unfortunately there's no interface for std::set that lets you "splice" two sets in a way that doesn't reallocate the internal tree nodes, so this is more or less as good as you can get.
Here's a variadic template approach:
template <typename RSet> void union(RSet &) { }
template <typename RSet, typename ASet, typename ...Rest>
void union(RSet & result, ASet const & a, Rest const &... r)
{
a.insert(a.begin(), a.end());
union(result, r...);
}
Usage:
std::set<T> result
union(result, s1, s2, s3, s4);
(Similar move-optimizations are feasible here; you can even add some branching that will copy from immutables but move from mutables, or from rvalues only, if you like.)
Here's a version using std::accumulate:
std::set<T> result =
std::accumulate(all_sets.begin(), all_sets.end(), std::set<T>(),
[](std::set<T> & s, std::set<T> const & t)
{ s.insert(t.begin(), t.end()); return s; } );
This version seems to rely on return value optimisation a lot, though, so you might like to compare it to this hacked up and rather ugly version:
std::set<T> result;
std::accumulate(all_sets.begin(), all_sets.end(), 0,
[&result](int, std::set<T> const & t)
{ result.insert(t.begin(), t.end()); return 0; } );
Usually, when using iterators we don't care about the actual category. Just let the implementation sort it out. That means, just change the function to accept any type:
template <typename T>
typename std::iterator_traits<T>::value_type sunion_over_iterator_range(T begin, T end)
{
typename std::iterator_traits<T>::value_type result;
for (T iter = begin; iter != end; ++ iter)
{
insert_all(result, *iter);
}
return result;
}
Note that I have used typename std::iterator_traits<T>::value_type, which is the type of *iter.
BTW, the iterator pattern is not related to OOP. (That doesn't mean it's a bad thing).

What is a C++ container with a "contains" operation?

I want to use a structure in which I insert integers, and then can ask
if (container.contains(3)) { /**/ }
There has to be something like this.
You can use std::vector.
std::vector<int> myVec;
myVec.push_back(3);
if (std::find(myVec.begin(), myVec.end(), 3) != myVec.end())
{
// do your stuff
}
You can even make a little helper function:
template <class T>
bool contains(const std::vector<T> &vec, const T &value)
{
return std::find(vec.begin(), vec.end(), value) != vec.end();
}
Here is how you would use it:
if (contains(myVec, 3)) { /*...*/ }
Simple algorithm:
template <typename Container>
bool contains(Container const& c, typename Container::const_reference v) {
return std::find(c.begin(), c.end(), v) != c.end();
}
You can customize it for more efficient search on some known containers:
template <typename Key, typename Cmp, typename Alloc>
bool contains(std::set<Key,Cmp,Alloc> const& s, Key const& k) {
return s.find(k) != s.end();
}
template <typename Key, typename Value, typename Cmp, typename Alloc>
bool contains(std::map<Key,Value,Cmp,Alloc> const& m, Key const& k) {
return m.find(k) != m.end();
}
And this way you obtain a single algorithm that performs the search on any container type, and is special cased to be faster on those containers which are ordered.
find on an unsorted vector is O(n).
std::set supports O(log n) insertions and lookups and is a good choice.
std::tr1::unordered_set provides a similar interface but supports near-constant-time lookups. It is the best choice if you have TR1 (or C++0x) and do not need to enumerate the elements in order.
What you want is the find_first_of method from the algorithms library. (or binary search, or anything along those lines)
http://www.cplusplus.com/reference/algorithm/find_first_of/
If you want to use a C++ standard container, due to its design, the containers themselves do not necessarily have "contains", but you can always use the find algorithm.
You should choose your container according to the characteristics of your dataset and the access "workload".
For a good reference of the containers and algorithms on the C++ standard library check http://www.cplusplus.com
Containers, Algorithms
If as it seems, your data is made of unique items, for which you want to associate a value, you probably will be well served by the map container. If all you care about is "membership", then set is a better choice.