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

loop through array with a custom function

46 views
Skip to first unread message

alessio211734

unread,
Feb 26, 2018, 3:29:25 PM2/26/18
to
Hello,
many time happen to do a series of similar algorithms where loop through array with adjacent iterator. Just a example to better understand

std::vector<float> v;
auto l=v.begin();
auto c=v.begin();
c++;
while (c!=v.end())
{
// here I do something with (*l) and (*c)
l++;
c++
}

how can I avoid to do a sort of copy and paste on my code when should
loop through array with adjacent iterator and apply a generic algoritm on the value of this iterator?
I think something with template but I don't known how.

Daniel

unread,
Feb 26, 2018, 4:16:39 PM2/26/18
to
On Monday, February 26, 2018 at 3:29:25 PM UTC-5, alessio211734 wrote:

> many time happen to do a series of similar algorithms where loop through
> array with adjacent iterator. Just a example
>
> std::vector<float> v;
> auto l=v.begin();
> auto c=v.begin();
> c++;
> while (c!=v.end())
> {
> // here I do something with (*l) and (*c)
> l++;
> c++
> }
>
> how can I avoid to do a sort of copy and paste on my code when should
> loop through array with adjacent iterator and apply a generic algoritm on > the value of this iterator?

Perhaps something like

#include <vector>
#include <iostream>

template <class Iterator,class F>
void process(Iterator l, Iterator end, F f)
{
if (l != end)
{
auto c = l + 1;
while (c != end)
{
f(c, l);
c++;
l++;
}
}
}

int main()
{
std::vector<float> v = {1,2,3};

auto f = [](std::vector<float>::iterator c,
std::vector<float>::iterator l)
{
std::cout << "do something with " << *c << " and " << *l <<
std::endl;
};

process(v.begin(), v.end(), f);
}

Daniel

unread,
Feb 26, 2018, 4:23:05 PM2/26/18
to
On Monday, February 26, 2018 at 4:16:39 PM UTC-5, Daniel wrote:
>
> Perhaps something like

or

#include <vector>
#include <iostream>

template <class Iterator,class F>
void process(Iterator l, Iterator end, F f)
{
if (l != end)
{
auto c = l + 1;
while (c != end)
{
f(*c, *l);
c++;
l++;
}
}
}

int main()
{
std::vector<float> v = {1,2,3};

auto f = [](float c, float l)
{std::cout << "do something with " << c << " and " << l << std::endl; };
process(v.begin(), v.end(), f);
}

Paavo Helde

unread,
Feb 26, 2018, 4:48:03 PM2/26/18
to
My attempt without lambdas:

#include <iostream>
#include <vector>
#include <numeric>
#include <cassert>

template<class CONT>
class IterPair {
public:
using T = typename CONT::value_type;
using ITER = typename CONT::const_iterator;

IterPair(ITER it1, ITER it2) : it1_(it1), it2_(it2) {
}
std::pair<const T&, const T&> operator*() const {
return std::pair<const T&, const T&>(*it1_, *it2_);
}
bool operator!=(const IterPair& b) {
return it1_ != b.it1_ && it2_ != b.it2_;
}
void operator++() {
++it1_;
++it2_;
}
private:
ITER it1_, it2_;
};

template<class CONT>
class AdjacentIterWrapper {
public:
using const_iterator = IterPair<CONT>;
AdjacentIterWrapper(const CONT& c) : c_(c) {
assert(!c.empty());
}
const_iterator begin() {
return const_iterator(c_.begin(), c_.begin()+1);
}
const_iterator end() {
return const_iterator(c_.end(), c_.end());
}
private:
const CONT& c_;
};

template<class CONT>
AdjacentIterWrapper<CONT> IterateAdjacent(const CONT& c) {
return AdjacentIterWrapper<CONT>(c);
}

int main() {
std::vector<float> v(100);
std::iota(v.begin(), v.end(), 0.0f);

for (auto x: IterateAdjacent(v)) {
// here I do something with (*l) and (*c)
std::cout << "do something with " << x.first << " and " << x.second <<
"\n";
}
}

Öö Tiib

unread,
Feb 26, 2018, 4:50:11 PM2/26/18
to
Vector has random access iterators so with those you can do
arithmetic and also since C++11 those have dereference operator [].

if (v.empty())
{
abort(); // or whatever is appropriate by your program logic
}
for (auto it = v.begin()+1; it!=v.end(); ++it)
{
// here do something with your it[-1] and it[0]
}

Daniel

unread,
Feb 26, 2018, 5:13:50 PM2/26/18
to
On Monday, February 26, 2018 at 4:50:11 PM UTC-5, Öö Tiib wrote:
>
> if (v.empty())
> {
> abort(); // or whatever is appropriate by your program logic
> }
> for (auto it = v.begin()+1; it!=v.end(); ++it)
> {
> // here do something with your it[-1] and it[0]
> }

Hard to beat that :-)

alessio211734

unread,
Feb 27, 2018, 4:19:35 AM2/27/18
to
Thanks

alessio211734

unread,
Feb 27, 2018, 4:20:08 AM2/27/18
to
Thanks you

alessio211734

unread,
Feb 27, 2018, 4:44:07 AM2/27/18
to
Hello, nice solution and if I want the possibity to have a circular buffer and for example print if this it's the buffer.
std::vector<float> v={1,2,3};
output:
1 2
2 3
3 1
How can I modify the template to get an iterator to circular buffer?

Paavo Helde

unread,
Feb 27, 2018, 6:03:27 AM2/27/18
to
Circular is slightly more tricky. Currently the IterPair class is
holding 2 iterators which are just incremented in operator++. One could
also store the container begin() and end() in the IterPair class and if
it2_ reaches the end, wrap it over to begin.

Cheers
Paavo

0 new messages