Construct vector from vector with conversion/scale - c++

All
suppose I got vector with data in cm, and would like to construct another vector but in mm (or mm with a shift, or ..., so it's not quite simple).
What would be good way to accomplish such task?
I wrote some code doing iterator adapter
struct scaling_iterator_adaptor {
...
};
vector v_mm{ scaling_iterator_adaptor{v_cm.begin()}, scaling_iterator_adaptor{v_cm.end()} };
Is there a better way to do such task? Conceptually different way?

If it is not essential to construct it with all the data contained already, you can use standard algorithms:
std::vector<double> v_cm{1, 3.14, 4.2};
std::vector<double> v_mm(v_cm.size());
std::transform(v_cm.cbegin(), v_cm.cend(), v_mm.begin(), [](double x){ return x * 10; });
You can use std::back_inserter if you don't want to prefill the target with zeroes.

Related

Can I pass a std::vector<std::unique_ptr<T>> as a vector of raw pointer without extra allocations?

Suppose I have the following function:
void sum(const std::vector<int*>& input) {
return ... ; // the sum
}
I store a vector of int pointers somewhere
...
std::vector<std::unique_ptr<int>> my_ints;
Is there a way to pass my_ints to sum() without any extra allocations such as an intermediate vector of the unique_ptrs converted to a vector of raw pointers?
Obviously, I could refacor sum() to take a vector of unique ptrs instead. Or overload it. But I'm hoping to find a way where I don't have to, and let the user decide whether or not to use a vector of unique_ptrs or raw pointers.
Not like you want, but you should think about sum() differently. It looks like an algorithm that operates on a range, so you should make it more like this:
template <typename It>
ValueType sum(It begin, It end) {
// ... iterate and calculate sum
return sum;
}
Then suddenly, you can start to use ranges to do cool things!
std::vector<std::unique_ptr<int>> my_ints;
auto range = my_ints | ranges::views::transform
(
[](auto smart_ptr) {
return smart_ptr.get();
}
);
This is a range that will transform as you use it! Then you could enter it into your sum() like this:
auto my_sum = sum(std::begin(range), std::end(range));
Also look up std::accumulate(), which does what you want here, I would say.
No, there is absolutely no way to pass those pointer values to that sum method without changing the method.

save result of for_each algorithm inside a vector

I have a functor and the overloaded operator() of it returns a double. In an easy way I can write:
int main(){
auto f=[](double t){return 1.0/(pow(7.0*t,2.0)+1.0);};
std::vector<double> nodes(n);
bestpolchevnod(f,nodes); //calculate nodes = f_i(cheby_point(i))
ChebyPoly c_p = ChebyPoly(nodes);//call the constructor with the calculated nodes
std::cout << c_p(0.6) << std::endl; //evaluate at c_p(0.6) as an approx of f(0.6)
};
Now it is possible to go through a set of values by using for_each() like:
std::vector<double> xpoints={0.4,0.5,0.6,0.7};
std::for_each(xpoints.begin(), xpoints.end(), ChebyPoly(nodes));
Is there a sharp/short way to save the calculated values of this algorithm directly for example in a vector? I know there are ways to do it otherwise. But I wonder if there is something similar like
std::vector<double> resvec(xpoints.size());
resvec.push_back(std::for_each(xpoints.begin(), xpoints.end(), ChebyPoly(nodes))); // wrong
std::for_each is the wrong algorithm, you want std::transform
std::vector<double> resvec(xpoints.size());
std::transform(xpoints.begin(), xpoints.end(), resvec.begin(), ChebyPoly(nodes));
Or without zero-initialising the elements of resvec
std::vector<double> resvec;
resvec.reserve(xpoints.size());
std::transform(xpoints.begin(), xpoints.end(), std::back_inserter(resvec), ChebyPoly(nodes));
Or without allocating a result, instead having a lazy view
auto result = xpoints | std::ranges::views::transform(ChebyPoly(nodes));

C++11, copying just one field into a vector

Say I have the following struct in C++
struct Foo {
double a;
int b;
};
And say I have a parameter to some function declared as follows:
const std::initializer_list<Foo> &args;
Is there an concise way to extract just one field from the elements in args to get, for instance, just an std::vector containing each b field from the original args list?
Of course, I know I could do this by just explicitly writing it out as a loop:
std::vector<int> result;
for(auto &x:args) {
result.push_back(x.b);
}
... but given that I can copy an entire initializer_list of any type to a like-typed vector in a single line of C++, just using functions like std::copy and std::back_inserter, I am wondering if there is a more elegant way to do this as well, using stl or C++11 facilities that may already exist.
You could use std::transform and add elements to the vector via std::back_inserter:
std::transform(std::begin(args), std::end(args), std::back_inserter(result),
[] (const Foo & foo) { return foo.b; });
If you find the lambda too verbose you can use std::mem_fn instead (credit goes to #StoryTeller).
std::transform(std::begin(args), std::end(args), std::back_inserter(result), std::mem_fn(&Foo::b));
But then again, your approach isn't necessary bad since it's pretty readable and does the job just fine (might have some performance issues tho).
One solution can be using linq++ like the following:
shared_ptr<vector<Foo>> foo_list;
// suppose foo_list is being filled
shared_ptr<vector> bs = from(foo_list).select(&_1 ->* &Foo::b).get();

Copy std::vector but apply lambda to each element

I have got a std::vector X of std::vector of, say, double in C++.
How can I transform X into a std::vector Y of int such that X[i].size() == Y[i] holds for all admissible indices i?
std::vector< std::vector<int> > X;
...
/* What I want to do should look as follows */
std::vector<int> Y = std::copy_and_transform( X, lambda_to_get_size );
Of course, this can be realized with a loop, but in C++11 we would like to use lambdas instead. I have not found anything like that in std::algorithm. The standard tools seem to only give in place transformations that change the original vector and which do not allow changing the data type.
You can use std::transform:
std::vector<int> Y;
std::transform(X.cbegin(), X.cend(), std::back_inserter(Y), [](const std::vector<int>& value) {
return value.size();
});

How to get Vector of Complex numbers from two vectors (real & imag)

I have two vectors of floats and i want them to become one vector of Complex numbers. I'm stuck. I don't mind using iterators, but i am sure it'd be rediscovering the wheel i'm not informed about. Is my code leading me in the right direction?
typedef std::vector<float> CVFloat;
CVFloat vA, vB;
//fil vectors
typedef std::complex<CVFloat> myComplexVector;
myComplexVector* vA_Complex = new myComplexVector(vA, vB);
The code above is going through the compiler correctly, but when i want to get single numbers from myComplexVector using iterator i get error "Undefined symbol 'const_iterator'" (Borland C++)
myComplexVector::const_iterator it = vA_Complex->begin();
Here you are creating a "complex" object whose real and imaginary parts are vectors of floats.
Maybe what you actually want to do is creating a vector of complex objects whose real and imaginary parts are floats?
EDIT: myComplexVector is not a vector, is a complex. That's why a const_iterator for it is not defined.
Whay not do it much much easier?
vector< complex<float> > result;
for( int i = 0; i < vA.size(); i++ ) {
result.push_back( complex<float>( vA[i], vB[i] ) );
}
The easiest way is just write the loop
myComplexVector cv;
for(CVFloat::iterator it1=vA.begin(), end1=vA.end(),
it2=vB.begin(), end2=vB.end();
it1!=end1 && it2 != end2; ++it1, ++it2)
cv.push_back(std::complex(*it1, *it2));
Edit: ... and follow Neil's advice to declare myComplexVector type properly.
You can create a general "zip" function taking iterators to both vectors, and a convertor functor and an output iterator:
template< typename at_It1, typename at_It2, typename at_Transform, typename at_Out >
void zip( at_It1 from1, const at_It1 to1,
at_It2 from2, const at_It2 to2,
at_Transform tranformer,
at_Out& av_Out ) {
while( from1 != to1 ) {
av_Out = transformer( *from1, *from2 );
++av_Out; ++from1; ++from2;
}
}
struct DoubleToComplex {
complex<double> operator()( const double d1, const double d2 ) const {
return complex<double>( d1, d2 );
}
};
zip( vA.begin(), vA.end(),
vB.begin(), vB.end(),
DoubleToComplex(),
std::back_inserter( vTarget ) );
And I wish there were such a function in the STL...
This doesn't make any sense:
typedef std::complex<CVFloat> myComplexVector;
surely you mean
typedef std::complex <float> ComplexFloat;
typedef std::vector <ComplexFloat> CFVector;
or something similar?
Once ou have it you can simply iterate over the float vectors (assuming they contain matching values) and add to your complex vector using push_back():
CFVector v;
for ( int i = 0; i < vA.size(); i++ ) {
v.push_back( ComplexFloat( vA[i], vB[i] ) );
}
A complex number is simply a pair of two real numbers a and b which denote the complex number a+bi. What exactly are you trying to do with the two vectors?
I understand your question that you want to combine a vector of real parts with a vector of imaginary parts into a vector of complex numbers.
std::complex has one template parameter which lets you chose the numerical represenation of the parts of the complex (i.e. if you want complex values based on double or float or even some custom number type...). The complex type then defines basic complex algebra in terms of the underlying type.
In your code you are trying to construct a complex type based on a vector of floats (i.e. a single complex value having a real and imaginary part being a vector), which is obviously wrong. Instead you want a vector of complex numbers of type float
You'd have to do something like:
// ...
typedef std::vector<std::complex<float> > floatComplexVector;
floatComplexVector vA_Complex; // No need to 'new' !?
for (CVFLoat::const_iterator itA = vA.begin(), itB = vB.begin();
itA != vA.end() && itB != vB.end();
++itA,++itB)
vA_Complex.push_back(std::complex<float>(*itA, *itB));
Remarks:
In most cases it isn't necessary to create containers such as vectors on the heap (i.e. using new) Try to avoid this.
Unfortunately the C++ standard library doesnt contain a combining iterator (i.e. one that "automatically" combines two sequences) which would allow a more elegant solution (see Boost Zip iterator for a general idea).