Is there an STL algo to fill a vector with product of 2 othervectors?

S

Steve555

Hi

I'm looking for an algorithm that takes 2 vectors and a function
pointer as arguments?
I want to use the function pointer to calculate a result e.g. the
product, and put the result either in place, or in a third vector.

I've looked through the list of algorithms and there doesn't appear to
be one.
transform() is the closest, but alas works on only a single vector.

Thanks

Steve

(I know I could write the whole thing from scratch, but I'm trying to
get in to the habit of using STL where possible)
 
S

Steve555

There are two versions of transform. One works on a single input range
and the other works on two input ranges. The latter sounds like just
what you need.

--
  Pete
Roundhouse Consulting, Ltd. (www.versatilecoding.com) Author of "The
Standard C++ Library Extensions: a Tutorial and Reference
(www.petebecker.com/tr1book)

Thanks Pete, hadn't spotted the second version.
I have a simple example working with multiplies<int>()
, but what about an arbitrary functor, how do I declare the arguments?
e.g: (where in1, in2, out, are my 3 vectors)

void pointlessCalc(in1, in2, out)
{
out = (in1 + 1) * (in2 +2);
}

Steve
 
J

jason.cipriani

Thanks Pete, hadn't spotted the second version.
I have a simple example working with multiplies<int>()
, but what about an arbitrary functor, how do I declare the arguments?
e.g: (where in1, in2, out, are my 3 vectors)

See:

http://www.sgi.com/tech/stl/transform.html

Specifically, your functor must follow this:

http://www.sgi.com/tech/stl/BinaryFunction.html

For example:

template <typename T> bool equals (const T &a, const T &b) {
return a == b;
}

void somewhere () {

std::vector<int> x, y;
x.push_back(1);
x.push_back(2);
y.push_back(2);
y.push_back(2);

std::vector<bool> result(x.size());
std::transform(x.begin(), x.end(), y.begin(), result.begin(),
equals<int>);

assert(result[0] == false);
assert(result[1] == true);

}

void pointlessCalc(in1, in2, out)
{
   out = (in1 + 1) * (in2 +2);

}

You'd want to return the value:

out pointlessCalc (in1, in2);


Jason
 
J

James Kanze

I'm looking for an algorithm that takes 2 vectors and a
function pointer as arguments? I want to use the function
pointer to calculate a result e.g. the product, and put the
result either in place, or in a third vector.
I've looked through the list of algorithms and there doesn't
appear to be one. transform() is the closest, but alas works
on only a single vector.

There are two versions of std::transform. The following code
should do the trick:
assert( v1.size() == v2.size() ) ;
std::transform( v1.begin(), v1.end(),
v2.begin(),
std::back_inserter( v3 ),
std::multiplies< double >() ) ;
 
S

Steve555

Thanks Pete, hadn't spotted the second version.
I have a simple example working with multiplies<int>()
, but what about an arbitrary functor, how do I declare the arguments?
e.g: (where in1, in2, out, are my 3 vectors)

See:

http://www.sgi.com/tech/stl/transform.html

Specifically, your functor must follow this:

http://www.sgi.com/tech/stl/BinaryFunction.html

For example:

template <typename T> bool equals (const T &a, const T &b) {
        return a == b;

}

void somewhere () {

        std::vector<int> x, y;
        x.push_back(1);
        x.push_back(2);
        y.push_back(2);
        y.push_back(2);

        std::vector<bool> result(x.size());
        std::transform(x.begin(), x.end(), y.begin(), result.begin(),
equals<int>);

        assert(result[0] == false);
        assert(result[1] == true);

}
void pointlessCalc(in1, in2, out)
{
   out = (in1 + 1) * (in2 +2);

You'd want to return the value:

out pointlessCalc (in1, in2);

Jason

Thanks for the example Jason, I wasn't sure whether it was expecting
values, or iterators in to the containers.
 
S

Steve555

There are two versions of std::transform.  The following code
should do the trick:
    assert( v1.size() == v2.size() ) ;
    std::transform( v1.begin(), v1.end(),
                    v2.begin(),
                    std::back_inserter( v3 ),
                    std::multiplies< double >() ) ;

--
James Kanze (GABI Software)             email:[email protected]
Conseils en informatique orientée objet/
                   Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34

Thanks James, but I wasn't sure why you used std::back_inserter()?
 
R

red floyd

Steve555 said:
Thanks James, but I wasn't sure why you used std::back_inserter()?

because that will push_back() the results onto the v3. Otherwise, you
risk running off the end of the resultant, especially if it's empty.
 
S

Steve555

because that will push_back() the results onto the v3.  Otherwise, you
risk running off the end of the resultant, especially if it's empty.

Thanks Red, but, Doh! This is bad news! I thought the whole point of
using these smart containers was that they grew to accomodate whatever
was put in to them?
When I use this (and other?) algorithms, they might write in to
unallocated memory if I don't tell them not to?
When designing this algorithm, how could it have been seen as a good
idea for it to default to a behavior that would not allocate the
correct memory? If you supply an iterator to a new vector to store the
transform of other vectors, what else could you possibly intend?

(OK, it's not so much trouble to add it, but it does seem like adding
the redundant instruction DontCrash() ;) )

Steve
 
K

Kai-Uwe Bux

Steve555 said:
Thanks Red, but, Doh! This is bad news! I thought the whole point of
using these smart containers was that they grew to accomodate whatever
was put in to them?

They do, but you have to actually _put_ an item into them. That is what
push_back(), push_front(), and insert() do. Note that operator[] will _not_
put an item into the container.
When I use this (and other?) algorithms, they might write in to
unallocated memory if I don't tell them not to?

Yes, you have to tell them.
When designing this algorithm, how could it have been seen as a good
idea for it to default to a behavior that would not allocate the
correct memory?

You are confused. The algorithm does not even know about the container. The
algorithm only sees the iterators. In the case of an output_iterator, the
file will grow as you write items; in the case of an insert_iterator, the
If you supply an iterator to a new vector to store the
transform of other vectors, what else could you possibly intend?

How is the algorithm supposed to know that the vector is _new_? All it sees
(OK, it's not so much trouble to add it, but it does seem like adding
the redundant instruction DontCrash() ;) )

No.

BTW: You could write a drop in replacement for std::vector<> that makes the
vector grow when iterators move past the end. However, that has an
overhead.


Best

Kai-Uwe Bux
 
J

jason.cipriani

Thanks Red, but, Doh! This is bad news! I thought the whole point of
using these smart containers was that they grew to accomodate whatever
was put in to them?
When I use this (and other?) algorithms, they might write in to
unallocated memory if I don't tell them not to?
When designing this algorithm, how could it have been seen as a good
idea for it to default to a behavior that would not allocate the
correct memory? If you supply an iterator to a new vector to store the
transform of other vectors, what else could you possibly intend?

(OK, it's not so much trouble to add it, but it does seem like adding
the redundant instruction DontCrash() ;)  )

Steve


You do not need to use back_insert_iterator if you can ensure that the
destination's size is large enough to hold the results. From the
example I gave you earlier:

std::vector<int> x, y;
x.push_back(1);
x.push_back(2);
y.push_back(2);
y.push_back(2);

std::vector<bool> result(x.size());
std::transform(x.begin(), x.end(), y.begin(), result.begin(),
equals<int>);

Note that 'result' is constructed with the appropriate initial size,
and back_insert_iterator is not necessary.

On the other hand, if 'result' is empty, back_insert_iterator can be
used to automagically append elements as necessary. Note that the use
of back_insert_iterator on a vector will cause the output to be
*appeneded* to it.

You would benefit greatly from thoroughly reading the relevant
documentation here:

http://www.sgi.com/tech/stl/transform.html
http://www.sgi.com/tech/stl/OutputIterator.html
http://www.sgi.com/tech/stl/back_insert_iterator.html
http://www.sgi.com/tech/stl/Vector.html (see constructor that takes
size)

Jason
 
J

James Kanze

Thanks James, but I wasn't sure why you used
std::back_inserter()?

Just to have an example. In the above code, the results are put
into a third, initially empty array. If you want them to
replace the contents of one of the original arrays, you
v1.begin() or v2.begin() instead. (The advantage of using
back_inserter here is that it makes it clear that this argument
is the output, since a back_insert_iterator can only be used for
output.)
 
J

James Kanze

It's not redundant.
STL algorithms write their output to sequences. An output
sequence is designated by a single iterator. If that iterator
points to the beginning of a vector or an array you can write
onto the elements of the vector without having to change its
size, provided it's at least as large as the number of things
you're going to write. But the iterator can also be an insert
iterator, in which case it inserts new elements into a
container.

And not to forget: there are three different types of insertion
iterator. I could have just as easily used front_inserter, or
inserter, with an additional iterator argument specifying where
I wanted to insert.
 
S

Steve555

Yes, I deliberately left that unsaid to encourage discovery.

--
  Pete
Roundhouse Consulting, Ltd. (www.versatilecoding.com) Author of "The
Standard C++ Library Extensions: a Tutorial and Reference
(www.petebecker.com/tr1book)

Thanks to everyone for the explanations, the help is so much clearer
than I'm reading from books.

As Kai said, I was confused, I assuumed that behind the scenes the
algorithm _did_ have a way of knowing about the containers, from the
iterators.
Jason, I do read the sgi.com descriptions (as they tend to appear 1st
in searches.) They're a great reminder reference for the algos you
already know, but I have to be honest, I find them a bit impenetrable
when you're already confused.

I take the points about both efficency, and the different insert
iterators. Guilty of thinking of iterators as magic black boxes!

Steve

*** Warning, flimsy excuse follows ***

An INPUT iterator is one that lets you read its OUTPUT.
An OUTPUT iterator lets you INPUT data in to it.
I'm a sound engineer, so the above is counter-intuitive to me.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,995
Messages
2,570,230
Members
46,817
Latest member
DicWeils

Latest Threads

Top