2

I am trying to find an elegant way to do the following loop:

std::vector<A> a = {...};
std::vector<B> b = {...}; # assume a.size() == b.size()

for (int i = 0; i < a.size() ; ++i){
    a[i].Method(b[i]);
}

I am expecting some sort of standard algorithm that could do that for me, but maybe it doesn't exists. Maybe something like:

std::apply(a.begin(),a.end(),b.begin(),Method)

Thank you if you know any function that exists that can do it.

Gophys
  • 51
  • 5
  • 3
    What did you not like about a simple loop approach you showed? – Killzone Kid Mar 28 '18 at 13:03
  • I think it is not elegant and maybe some optimization could be done by standard library. Just like the std::accumulate has been created instead of using a loop to do the same. – Gophys Mar 28 '18 at 13:05
  • [Iterate over two or more containers simultaneously](https://stackoverflow.com/q/12552277/1460794). – wally Mar 28 '18 at 13:06

5 Answers5

1

You could use std::transform

transform(a.begin(), a.end(), b.begin(), result.begin(), [&](A * obj, B * obj2) {return obj->Method(obj2); });

http://www.cplusplus.com/reference/algorithm/transform/

You have to #include <algorithm>, to use this function.

Y.S
  • 311
  • 1
  • 10
1

Just a try:

auto&& it=b.begin();
for_each(a.begin(), a.end(),[&](value_type& v){v.Method(*it++)});
choxsword
  • 3,187
  • 18
  • 44
1

It's a pretty special use case, but you can always cook something up yourself.
Something along these lines, perhaps? (Far from industrial strength implementation.)

template<typename a_iterator, typename b_iterator>
void zip_apply(a_iterator a_it, a_iterator a_end, b_iterator b_it, void (A::*fn)(const B&)
{
    std::for_each(a_it, a_end, [&b_it, fn](A& a) { a.*fn(*b_it++); })
}

std::vector<A> as = ...;
std::vector<B> bs = ...;
zip_apply(as.begin(), as.end(), bs.begin(), &A::Method);
molbdnilo
  • 64,751
  • 3
  • 43
  • 82
  • That would be great in the standard library. but it seems it does'nt exists. As i won't use it in my code more than once I won't use your solution but thank you. – Gophys Mar 28 '18 at 13:36
0

It seems std::transform most likely meets your requirement:

template< class InputIt, class OutputIt, class UnaryOperation >
OutputIt transform( InputIt first1, InputIt last1, OutputIt d_first,
                    UnaryOperation unary_op );
James Dong
  • 404
  • 3
  • 7
  • 1
    Not quite. OP want's to do a.func(b) for ranges A and B. Transform will apply func(a) from range A and put the result into range B. OP is asking for more of a zip function, which I'm not sure exists in the standard library. – Kevin Mar 28 '18 at 13:26
  • Another answer is a bit more precise with an example of how to you it, but thank you, it is indeed close to what I wanted. Plus the signature with the binary operator fit my need a bit more. – Gophys Mar 28 '18 at 13:30
0

If you’re only going to do the thing once than just use a loop, if you going to do it regular, then why not make your own func with an interface you like. Below is how I would go about it.

// Non iterator version
template<class A, class B>
void apply_methodX(std::vector<A> & vec_a, std::vector<B> & vec_b, size_t len, void(A::*method)(B)) {
    for (size_t i(0); i < len; ++i) {
        (vec_a[i].*method)(vec_b[i]); 
    }
}

// Iterator version
template<class A, class B>
void apply_method_it(typename std::vector<A>::iterator first_a, typename std::vector<A>::iterator last_a, typename std::vector<B>::iterator first_b, void(A::*method)(B)) {
    for (; first_a != last_a; ++first_a, ++first_b) {
         (*first_a.*method)(*first_b);
    }
}

Void main{
    std::vector<A> vec_a;
    std::vector<B> vec_b;
    // assign blah blah into vectors…
    apply_methodX<A, B>(vec_a, vec_b, vec_a.size(), &A::A_method);
    apply_method_it<A, B>(vec_a.begin(), vec_a.end(), vec_b.begin(), &A::A_method);
}
Joe Oram
  • 23
  • 3