List comprehension in c++
An attempt to mimic the handiness of list comprehension in python.
PYTHON
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
nums = [1,2,3,4] | |
result = [x*x for x in nums] |
C++ with macros 'each' and 'only'
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
set nums = {1,2,3,4}; | |
auto result = in(nums, each(x, x*x)); // insert all elements multiplied by themselves | |
auto result = in(nums, each(x, (x>2)?x*x:x)); // insert all elements but only multiply those that fulfill the condition | |
auto result = in(nums, only(x, x<2, x*x)); // insert only the elements that fulfill the condition | |
auto result = in(nums, only(x, x<4 && cout<<x, x*x)); // insert and print only the elements that fulfill the condition (prints: 123) |
C++ with lambda instead of macros
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
set nums = {1,2,3,4}; | |
auto result = in(nums, [](auto x) { return x*x; }); |
The classes can be placed in a header file:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <array> | |
template <typename T, size_t S> | |
class into : public std::array<T,S> | |
{ | |
public: | |
into (std::array<T,S>& input, auto func) | |
{ | |
for (size_t i=0; i<this->size(); i++) | |
{ | |
(*this)[i] = func(input[i]); | |
} | |
} | |
into (std::array<T,S>& input, auto condition, auto func) | |
{ | |
for (size_t i=0; i<this->size(); i++) | |
{ | |
if (!condition(input[i])) continue; | |
(*this)[i] = func(input[i]); | |
} | |
} | |
}; | |
template<typename T, template<typename...> class C, typename... Args> | |
class in | |
{ | |
public: | |
in (C<T, Args...>& input, auto condition, auto func) | |
{ | |
for (auto inp=input.begin(); inp!=input.end(); inp++) | |
{ | |
if (!condition(*inp)) continue; | |
(void)items.insert(items.end(),func(*inp)); | |
} | |
} | |
in (C<T, Args...>& input, auto func) | |
{ | |
for (auto inp=input.begin(); inp!=input.end(); inp++) | |
{ | |
(void)items.insert(items.end(),func(*inp)); | |
} | |
} | |
auto begin () const { return items.begin(); } | |
auto end () const { return items.end(); } | |
auto size () const { return items.size(); } | |
const auto& operator [] (const size_t& i) const { auto iter = items.begin(); std::advance(iter,i); return *iter; } | |
operator auto () const { return items; } | |
private: | |
C<T, Args...> items; | |
}; | |
#define only(x,c,f) [](const auto& x) {return bool(c);}, [](const auto& x) {return f;} | |
#define each(x,f) [](const auto& x) {return f;} |
And then it can be used with different containers like this:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <vector> | |
#include <deque> | |
#include <map> | |
#include <set> | |
#include <list> | |
#include <string> | |
using namespace std; | |
int main() | |
{ | |
switch(6) | |
{ | |
case 1: | |
{ | |
array nums = {1,2,3,4}; | |
auto result = into(nums, only(x, x<3, x*x)); | |
return result[1]; | |
} | |
case 2: | |
{ | |
string letters = "hello"; | |
auto result = in(letters, each(x, toupper(x))); | |
return result[1]; | |
} | |
case 3: | |
{ | |
list nums = {1,2,3,4}; | |
auto result = in(nums, each(x, (x>2)?x*x:x)); | |
return result[1]; | |
} | |
case 4: | |
{ | |
set nums = {1,2,3,4}; | |
auto result = in(nums, only(x, x<3, x*x)); | |
return result.size(); | |
} | |
case 5: | |
{ | |
deque nums = {1,2,3,4}; | |
auto result = in(nums, each(x, x*x)); | |
return result[1]; | |
} | |
case 6: | |
{ | |
vector nums = {1,2,3,4}; | |
auto result = in(nums, each(x, (true)?x*x:x)); | |
return result[1]; | |
} | |
case 7: | |
{ | |
map<int,string> nums = { {1,"one"}, {2,"two"}, {3,"three"}, {4,"four"} }; | |
auto result = in(nums, each(x, make_pair(x.first*x.first,x.second))); | |
return result[1].first; | |
} | |
} | |
return 0; | |
} |
It can be implemented in one function à la:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
template<typename T, template<typename...> class C, typename... Args> | |
C<T, Args...> in (C<T, Args...>& input, auto func) | |
{ | |
C<T, Args...> items; | |
for (auto inp=input.begin(); inp!=input.end(); inp++) (void)items.insert(items.end(),func(*inp)); | |
return items; | |
} |
But I wanted to have a unified way to access the container after it's created
[Get it on github]