Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Return a transient sequence of results similar to LINQ iterator blocks

21 views
Skip to first unread message

Marcel Mueller

unread,
Sep 10, 2015, 4:14:20 PM9/10/15
to
Is there a pattern to return a result set from a function without to
fill a temporary container with the results? I.e. a concept similar to
the .Net iterator blocks.

E.g.:

#include <stdio.h>
#include <vector>

using namespace std;

vector<int> even_numbers(vector<int> numbers)
{
vector<int> result;
for (int num : numbers)
if ((num & 1) == 0)
result.push_back(num);
return result;
}

int main()
{
for (int num : even_numbers(vector<int>({ 1,5,3,2,3,6,8 })))
printf("%i\t", num);
}

The function even_numbers just picks the even number from its input. But
it creates a collection with all the results. No problem in this simple
example, but when the input is large transient data instead of vector<>
this is no longer desirable.

So I would prefer to return a virtual container that just supports input
iteration and returns the requested results on the fly.

Of course, I could define my own container class and iterator class each
time, but I am looking for a simpler way to return an object with
required properties, since writing STL compatible containers is not that
easy.

Is there a common pattern for use cases like this?


Marcel

bartekltg

unread,
Sep 10, 2015, 5:24:30 PM9/10/15
to
On 10.09.2015 22:14, Marcel Mueller wrote:
> Is there a pattern to return a result set from a function without to
> fill a temporary container with the results? I.e. a concept similar to
> the .Net iterator blocks.
>
> E.g.:
>
> #include <stdio.h>
> #include <vector>
>
> using namespace std;
>
> vector<int> even_numbers(vector<int> numbers)

vector<int> even_numbers(const vector<int> &numbers)



> {
> vector<int> result;
> for (int num : numbers)
> if ((num & 1) == 0)
> result.push_back(num);
> return result;
> }



> int main()
> {
> for (int num : even_numbers(vector<int>({ 1,5,3,2,3,6,8 })))
> printf("%i\t", num);
> }
>
> The function even_numbers just picks the even number from its input. But
> it creates a collection with all the results. No problem in this simple
> example, but when the input is large transient data instead of vector<>
> this is no longer desirable.
>
> So I would prefer to return a virtual container that just supports input
> iteration and returns the requested results on the fly.
>
> Of course, I could define my own container class and iterator class each
> time, but I am looking for a simpler way to return an object with
> required properties, since writing STL compatible containers is not that
> easy.
>
> Is there a common pattern for use cases like this?

Maybe this will work.

http://www.boost.org/doc/libs/1_59_0/libs/iterator/doc/filter_iterator.html
Look at the examples.

This get you a pair of iterators that can skip, not a container,
so you can't use range based loop, but I think it isn't a big problem.


bartekltg

Luca Risolia

unread,
Sep 10, 2015, 5:34:36 PM9/10/15
to
Il 10/09/2015 22:14, Marcel Mueller ha scritto:
> for (int num : even_numbers(vector<int>({ 1,5,3,2,3,6,8 })))

what's wrong with:
for (int num : even_numbers({ 1,5,3,2,3,6,8 }))

anyway:

> The function even_numbers just picks the even number from its input.
> But it creates a collection with all the results. No problem in this
> simple example, but when the input is large transient data instead of
> vector<> this is no longer desirable.
>
> So I would prefer to return a virtual container that just supports
> input iteration and returns the requested results on the fly.

I am not sure I understood your question.

Are you talking about using/returning (a lighter) vector of wrappers,
similar to std::vector<std::reference_wrapper<int>>, for example:

http://en.cppreference.com/w/cpp/utility/functional/reference_wrapper

(see the examples there)

Also, although I do not clearly see what you are trying to achieve,
consider this alternative approach:

template <class F, class... Args>
void for_each_argument(F f, Args&&... args) {
std::array<int, sizeof...(Args)>{(f(std::forward<Args>(args)), 0)...};
}


for_each_argument([](int num) {
if (!(num&1)) printf("%i\t", num);
}, 1, 5, 3, 2, 3, 6, 8);

Öö Tiib

unread,
Sep 10, 2015, 5:48:38 PM9/10/15
to
On Friday, 11 September 2015 00:24:30 UTC+3, bartekltg wrote:
> On 10.09.2015 22:14, Marcel Mueller wrote:
> > Is there a pattern to return a result set from a function without to
> > fill a temporary container with the results? I.e. a concept similar to
> > the .Net iterator blocks.

...

> > Is there a common pattern for use cases like this?
>
> Maybe this will work.
>
> http://www.boost.org/doc/libs/1_59_0/libs/iterator/doc/filter_iterator.html
> Look at the examples.

+1

Also rest of the Boost.Iterator is worth eyeballing if you feel like
needing to make your own iterators.

mark

unread,
Sep 10, 2015, 6:04:00 PM9/10/15
to
If you are willing to use Boost (header only):

--------------------------------------------------------------------------
#include <iostream>
#include <vector>

#define BOOST_ALL_NO_LIB
#include <boost/range/adaptors.hpp>

using boost::adaptors::filtered;
using boost::adaptors::transformed;

auto filter_fn = [](const auto& elem) {
return elem % 2 == 0;
};

auto trans_fn = [](const auto& elem) {
return elem * 42;
};

auto print_range = [](const auto& range) {
for(const auto& elem : range) std::cout << elem << " ";
std::cout << std::endl;
};

int main() {
auto input = std::vector<int>({ 1,5,3,2,3,6,8 });
auto filtered_vec = input | filtered([](const auto& elem) {
return elem % 2 == 0;
});
print_range(filtered_vec);
auto filtered_vec2 = input | filtered(filter_fn);
print_range(filtered_vec2);

// can be stuffed into the loop statement
for(const auto& elem : input | filtered(filter_fn))
std::cout << elem << " ";
std::cout << std::endl;

// also multiply filtered elements by 42
auto trans_vec = input | filtered(filter_fn) | transformed(trans_fn);
print_range(trans_vec);
}
--------------------------------------------------------------------------

This is C++14, but with increasing levels of uglification things work
with earlier C++ versions.

"filtered_vec" is exactly what you want. It's not a container, but
rather an adapter that supports iteration.

(Your even check doesn't work on negative numbers on one's complement
platforms.)
0 new messages