Glueon
Glueon

Reputation: 4017

Transform and accumulate with C++11

Coming from Python I wonder if C++ nowadays has some good functional things there are in Python.

Currently I am trying to figure out how to produce a sum of some elements using indexes instead. For example with Python I would:

a = [ ... ]
b = [ ... ]

sum(map(lambda i: a[i] * 2 - b[i + 1], range(len(a)))

So here I generate a new array where each element is determined by some index arithmetic.

In STL there are transform and accumulate, but they take iterators as arguments. This would be OK if only on each step I needed to change a concrete element. Here I need to use index.

Also with transform I have to specify the array I need to put the results to. Is there a way the resulting array could be generated on the fly and then returned? Something like Python's map does.

Because in such case it's really easier to write a simple for-loop.

Upvotes: 0

Views: 1355

Answers (1)

Praetorian
Praetorian

Reputation: 109119

There's no need to create an intermediate array, just leave std::transform out of the picture. All you need is std::accumulate to sum the intermediate result. But, as you've noted, this involves jumping through a few hoops to get the index given an iterator.

int a[] = {10, 20, 30, 40};
int b[] = {1, 2, 3, 4, 5};

std::accumulate(std::begin(a), std::end(a), 0,
                [&](int acc, int& a_elem) {
                    auto index = std::distance(a, &a_elem);
                    return acc + a[index] * 2 - b[index + 1];
                })

Live demo

This can be cleaned up quite a bit if you can use Boost.Range instead. This will allow you to generate a range of integers that can be used as indices, very similar to your Python example.

boost::accumulate(boost::irange<unsigned>(0, boost::size(a)), 0,
                  [&](int acc, int index) {
                    return acc + a[index] * 2 - b[index + 1];
                  })

Live demo

Upvotes: 3

Related Questions