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

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

Related

Does the standard library have a comparator reversal mechanism?

I know the standard library has std::reverse_iterator<...>, which, given an iterator type, can be used to obtain its reverse (type).
Does it also have a similar mechanism for reversing comparators used for sorting/ordering? Something which takes a comparator type and produces the comparator corresponding to the reverse order (assuming the order is reversible)? e.g.
with std::reverse_comparator<std::greater<int>> being equivalent to std::less<int>?
C++17 introduces std::not_fn which will "replace" std::greater<int> by std::less_equal<int>.
which is not a correct comparer for std::sort/std::map.
Else in std, I don't think it exists one which "transform" into std::less<int>, but you can write your own easily, something like:
template <typename Comparer>
struct InvComparer
{
public:
explicit InvComparer(Comparer comparer) : comp(comparer) {}
template <typename T1, typename T2>
bool operator() (const T1& lhs, const T2& rhs) const { return comp(rhs, lhs); };
private:
Comparer comp;
};
Demo
There is not2, which would generate the the binary complement of the input functor. However, the complement of std::greater<T> is not equivalent to std::less<T>, but std::less_equal<T> which is not a valid comparator for most standard algorithms. C++17 is going to introduce a generic not_fn that works with non-binary functors as well.
There is no out of the box solution for std::less<T> -> std::greater<T> but it should be possible to implement. Perhaps:
template<class Pred>
auto
fancy_not2(Pred&& pred) {
return [pred=std::forward<Pred>(pred)](auto&& left, auto&& right){
return left != right
&& !pred(std::forward<decltype(left)>(left),
std::forward<decltype(right)>(right));
};
}

Mapping a vector of one type to another using lambda

I have a bit of code that looks like
B Convert(const A& a) {
B b;
// implementation omitted.
return b;
}
vector<B> Convert(const vector<A>& to_convert) {
vector<B> ret;
for (const A& a : to_convert) {
ret.push_back(Convert(a));
}
retun ret;
}
I was trying to rewrite this using lambdas but the code does not look more concise or more clear at all:
vector<B> Convert(const vector<A>& to_convert) {
vector<B> ret;
std::transform(to_convert.begin(),
to_convert.end(),
std::back_inserter(ret),
[](const A& a) -> B { return Convert(a); });
retun ret;
}
What I would really like to do is something like:
vector<B> Convert(const vector<A>& to_convert) {
return map(to_convert, [](const A& a) -> B { return Convert(a); });
}
Where map is a functional style map function that could be implemented as:
template<typename T1, typename T2>
vector<T2> map(const vector<T1>& to_convert,
std::function<T2(const T1&)> converter) {
vector<T2> ret;
std::transform(to_convert.begin(),
to_convert.end(),
std::back_inserter(ret),
converter);
retun ret;
}
Obviously the above is limited because it only works with vector, ideally one would want similar functions for all container types. At the end of the day, the above is still not better than my original code.
Why isn't there something like this (that I could find) in the stl?
You said it yourself, this map is not generic enough. std::transform on the other hand is, at the cost of more verbose interface. Another reason is that map, unlike std::transform forces new allocation, which is not always desirable.
template<class F, class R, class Out>
struct convert_t {
F f;
R r;
// TODO: upgrade std::begin calls with Koenig lookup
template<class D>
operator D()&&{
D d;
std::transform(
std::begin(std::forward<R>(r)),
std::end(std::forward<R>(r)),
std::back_inserter(d),
std::forward<F>(f)
);
return d;
}
template<template<class...>class Z, class Result=Z<
typename std::decay<Out>::type
>>
Result to()&&{return std::move(*this);}
};
template<class F, class R,
class dF=typename std::decay<F>::type,
class dR=typename std::decay<R>::type,
class R_T=decltype(*std::begin(std::declval<dR>())),
class Out=typename std::result_of<dF&(R_T)>::type
>
convert_t<dF,dR,Out>
convert( F&& f, R&& r ) { return {std::forward<F>(f), std::forward<R>(r)}; }
which gives us this:
std::vector<int> vec{1,2,3};
auto r = convert(Convert, vec).to<std::vector>();
for (auto&& x:r)
std::cout << x << '\n';
std::vector<double> r2 = convert(Convert, vec);
for (auto&& x:r)
std::cout << x << '\n';
live example.
This only handles sequence container output, as std::back_inserter would have to be swapped for std::inserter or somesuch for associative containers.
Also, some associative containers (like map) don't like being passed a pair -- they want Key,Value. Expressing that generically is tricky.
The standard library takes care to separate containers, and their traversal. By having std algorithms take containers directly, you'd lose the possibility of using different iterator types for different methods of traversal.
For example, Boost.Iterator uses specifically this clean separation to provide a neat collection of every traversal method you could dream of.
Note also that not all iterators traverse actual containers : std::back_inserter (which you should use instead of ret.begin() if you don't want to fall into unallocated space) actually constructs the container as it goes, and std::ostream_iterator is completely unrelated to any container as it pushes what's assigned to it to a stream.
Of course, nothing stops you from making a thin wrapper for the classic begin/end traversal :
template <
template <class...> class Container,
class Transform,
class ContainerT,
class... ContainerParams
>
auto map(Container<ContainerT, ContainerParams...> const &container, Transform &&transform) {
using DestT = std::result_of_t<Transform(ContainerT const&)>;
Container<DestT, ContainerParams...> res;
using std::begin;
using std::end;
std::transform(
begin(container),
end(container),
std::inserter(res, end(res)),
std::forward<Transform>(transform)
);
return res;
}
(live on Coliru)

Container version of C++ sort

I was reading Stroustrup's blog on c++ (http://isocpp.org/blog/2014/12/myths-3) when I found an intersting piece of code:
void do_my_sort(vector<double>& v)
{
sort(v,[](double x, double y) { return x>y; }); // sort v in decreasing order
}
int main()
{
vector<double> vd;
// ... fill vd ...
do_my_sort(v);
// ...
}
Notice that the sort does not use the traditional sort(v.begin(), v.end(), ...) which Stroustrup explains:
I used a container version of sort() to avoid being explicit about the
iterators.
However, I tried the same code on my C++11 compiler but it fails to compile. I also tried the same on a C++14 compiler using ideone but it too fails to compile, saying that there is no matching call to sort.
Why is this?
Also, Stroustrup next mentions:
I could go further and use a C++14 comparison object:
sort(v,greater<>()); // sort v in decreasing order
I have used comparators like great<>() for sort in C++11 also. Why is he stating that this is a C++14 comparison object?
He wrote that himself, it is not standard. Thus you cannot find it in the standard library. You could implement it like this:
template <class Container, class Comp>
void sort (Container& cont, Comp comp) {
using std::begin;
using std::end;
std::sort(begin(cont), end(cont), comp);
}
As Clukester pointed out, there is also boost::sort that offers this functionality.
I have used comparators like great<>() for sort in C++11 also. Why is he stating that this is a C++14 comparison object?
The C++14 comparison functors have the added ability to take forwarding references for its operator() method and deduced return types. The template argument for the Function Objects collection has been changed to have a default argument of type void and using specialization for that type.
template< class T = void >
struct greater
{
constexpr bool operator()(const T &lhs, const T &rhs) const;
};
template<>
struct greater<void>
{
template< class T, class U>
constexpr auto operator()( T&& lhs, U&& rhs ) const
-> decltype(std::forward<T>(lhs) > std::forward<U>(rhs));
};
Perhaps he is using Boost's sort, not the standard sort as one would expect. So it's boost::sort, not std::sort.

operator overloading and template specialization

I have a template class template<typename T, typename R>. R is of type vector<T*> or list<T*>.
I want my class to overload [] operator so that in case it is a vector I will use the built in [] operator for efficiency and in case it's a list I will implement it with iterator.
To me it sounds like a job for template specialization so I thought to write something like this:
template<typename T, typename R>
T& tContainer_t<T, R>::operator[]( unsigned i )
{
//TODO with iterators
}
template<>
T& tContainer_t::operator[]<T, std::vector<T*> >( unsigned i )
{
// TODO with built in [] operator
}
This is wrong and the compiler doesn't allow this.
Is there a way to make it work, or should I use typeid() to differ the two objects at runtime and act accordingly ?
The way to do it with templates is to make a static helper function in a class that can be partially specialized. However, what I would do is:
template<typename T, typename R>
T& tContainer_t<T, R>::operator[]( unsigned i )
{
//assuming that the container refernce is name container;
typename R::iterator itr = container.begin();
std::advance(itr, i);
return *itr;
}
std::advance is guaranteed that for a container with random access iterators (such as vector), it is constant time (basically, it does iterator + n), it can be as fast as doing the pointer lookup vector performs. Otherwise, it does iterator++ n times, which will be linear time. The const version will use const_iterator, but is essentially the same.
Doing it this way will let you properly handle different types of containers (not just vector and list), without having to modify the code.
You don't have to overload the operator. The library aleady contains overloaded functions to help you. std::advance will move an iterator, taking advantage of operator+() for random access iterators.
template<typename T, typename R>
T& tContainer_t<T, R>::operator[]( unsigned i )
{
typename R::iterator it = myContainer.begin();
std::advance(it, i);
return *it;
}

C++ container/array/tuple consistent access interface

Is there, perhaps in boost, consistent element access semantics which works across containers?
something along the lines of:
element_of(std_pair).get<1>();
element_of(boost_tuple).get<0>();
element_of(pod_array).get<2>();
in principle i can write myself, but I would rather not reinvent the wheel.thanks
Containers have different ways of accessing them because they are inherently different. The closest that you get in the STL are iterators. All of the standard containers have iterators, so you can iterate over them and use the same algorithms on them using those iterators. However, what each iterator contains differs depending on the container (must just have the element, but maps have pairs). And if you're looking at pair as a container, it's not going to fit in with the rest because it doesn't have iterators.
In most cases, using iterators solves the problem. However, it obviously doesn't completely solve the problem, and the STL does not have a solution for it. Boost may, but I'm unaware of one.
The main point, however, is that containers are inherently different and to a great extent are not meant to be interchangeable. By using standard iterators, most containers can be swapped for one another fairly easily. But it doesn't generally make sense to swap one container for another without changing some of the code around it because they act so differently. I believe that Scott Meyers makes a point of this in his book "Effective STL."
If you're really trying to make the various containers interchangeable, I'd suggest rethinking that and looking more closely at what you're doing. Odds are that that's not the best idea. Now, it may very well be a good idea for your particular application - I certainly can't say without knowing anything about it, and you'd be the best judge of that - but in the general case, making containers truly interchangeable is a bad idea. Iterators make it possible to reuse many algorithms on them, but even there, the type of algorithms that you can use on a particular container varies depending on the type of iterators that that container uses (random access, bi-directional, etc.).
So, no, I'm not aware of a pre-existing solution for accessing container elements other than iterators, but generally speaking, I'd advise against attempting it. Containers are not truly interchangeable and are not meant to be.
I'm not aware of such a thing.
You could most probably just implement a free get function for the types you're interested in. Boost.Tuple already has it. std::pair has it in C++0x. And the rest shouldn't be too complicated.
E.g
#include <iostream>
#include <utility>
#include <vector>
#include <boost/tuple/tuple.hpp>
namespace getter
{
template <size_t Index, class Container>
typename Container::reference get(Container& c)
{
return c[Index];
}
template <size_t Index, class Container>
typename Container::const_reference get(const Container& c)
{
return c[Index];
}
template <size_t Index, class T>
T& get(T *arr)
{
return arr[Index];
}
namespace detail {
template <size_t Index, class T, class U>
struct PairTypeByIndex;
template <class T, class U>
struct PairTypeByIndex<0u, T, U>
{
typedef T type;
type& operator()(std::pair<T, U>& p) const { return p.first; }
const type& operator()(const std::pair<T, U>& p) const { return p.first; }
};
template <class T, class U>
struct PairTypeByIndex<1u, T, U>
{
typedef U type;
type& operator()(std::pair<T, U>& p) const { return p.second; }
const type& operator()(const std::pair<T, U>& p) const { return p.second; }
};
}
template <size_t Index, class T, class U>
typename detail::PairTypeByIndex<Index, T, U>::type& get(std::pair<T, U>& p)
{
return detail::PairTypeByIndex<Index, T, U>()(p);
}
template <size_t Index, class T, class U>
const typename detail::PairTypeByIndex<Index, T, U>::type& get(const std::pair<T, U>& p)
{
return detail::PairTypeByIndex<Index, T, U>()(p);
}
using boost::get;
}
int main()
{
boost::tuple<int, int> tuple(2, 3);
std::cout << getter::get<0>(tuple) << '\n';
std::vector<int> vec(10, 1); vec[2] = 100;
std::cout << getter::get<2>(vec) << '\n';
const int arr[] = {1, 2, 3, 4, 5};
std::cout << getter::get<4>(arr) << '\n';
std::pair<int, float> pair(41, 3.14);
++getter::get<0>(pair);
const std::pair<int, float> pair_ref = pair;
std::cout << getter::get<0>(pair_ref) << ' ' << getter::get<1>(pair_ref) << '\n';
}
I'm not aware of any generic accessors that would work across all known definitions of containers in C++. However, Boost.Range can be used as such to some extent.
For better flexibility, you will likely need to implement it yourself. Perhaps scratching something along this:
struct container_accessor { ... }
template <typename Container>
container_accessor make_accessor(Container& c) { ... }
template <typename Container>
container_const_accessor make_accessor(Container const& c) { ... }
where and then specialise container_accessor for all containers you need.