I wanted to get a vector of distances between adjacent points in a vector:
struct Point { double x, y, z; }
vector<double> adjacent_distances( vector<Point> points ) {
...
}
I thought that stl::adjacent_difference() would do the trick for me if I simply provided a function that finds the distance between 2 points:
double point_distance( Point a, Point b ) {
return magnitude(a-b); // implementation details are unimportant
}
Thus, I was hoping that this would work,
vector<double> adjacent_distances( vector<Point> points )
{
vector<double> distances;
std::adjacent_difference( points.begin(), points.end(),
std::back_inserter(distances),
ptr_fun( point_distance ) );
return distances;
}
only to find that input and output vectors had to be of (practically) the same type because adjacent_difference() calls
output[0] = input[0]; // forces input and output to be of same value_type
output[1] = op( input[1], input[0] );
output[2] = op( input[2], input[1] );
....
which, sadly, is inconsistent with respect to how std::adjacent_find() works.
So, I had to convert my code to
double magnitude( Point pt );
Point difference( Point a, Point b ); // implements b-a
vector<double> adjacent_distances( vector<Point> points )
{
vector<Point> differences;
std::adjacent_difference( points.begin(), points.end(),
std::back_inserter(differences),
ptr_fun( point_difference ) );
vector<double> distances;
std::transform( differences.begin(), differences.end(),
std::back_inserter(distances),
ptr_fun( magnitude ) );
return distances;
}
NB: the first element of differences had to be removed for the function to behave correctly, but I skipped the implementation details, for brevity.
Question: is there a way I could achieve some transformation implicitly, so that I don't have to create the extra vector, and achieve a call to adjacent_difference() with input_iterator and output_iterator of different value_types ?
Probably this isn't so neat though, in this specific case, std::transform
with 2 input sequences might meet the purpose.
For example:
vector<double> adjacent_distances( vector<Point> points ) {
if ( points.empty() ) return vector<double>();
vector<double> distances(
1, point_distance( *points.begin(), *points.begin() ) );
std::transform( points.begin(), points.end() - 1,
points.begin() + 1,
std::back_inserter(distances),
ptr_fun( point_distance ) );
return distances;
}
Hope this helps
Indeed that adjacent_difference algorithm is logically broken (why should be the difference of the same time of the elements? Why is the first output element equal to the first one instead of getting an output sequence one item shorter than the input one (way more logical)?
Anyway I don't understand why you are punishing yourself by using a functional approach with C++ where clearly the code is going to be harder to write, harder to read, slower to compile and not faster to execute. Oh.. and let's not talk about the kind of joke error message you are going to face if there is any error in what you type.
What is the bad part of
std::vector<double> distances;
for (int i=1,n=points.size(); i<n; i++)
distances.push_back(magnitude(points[i] - points[i-1]));
?
This is shorter, more readable, faster to compile and may be even faster to execute.
EDIT
I wanted to check my subjective "shorter, more readable, faster to compile and may be faster to execute". Here the results:
~/x$ time for i in {1..10}
> do
> g++ -Wall -O2 -o algtest algtest.cpp
> done
real 0m2.001s
user 0m1.680s
sys 0m0.150s
~/x$ time ./algtest
real 0m1.121s
user 0m1.100s
sys 0m0.010s
~/x$ time for i in {1..10}
> do
> g++ -Wall -O2 -o algtest2 algtest2.cpp
> done
real 0m1.651s
user 0m1.230s
sys 0m0.190s
~/x$ time ./algtest2
real 0m0.941s
user 0m0.930s
sys 0m0.000s
~/x$ ls -latr algtest*.cpp
-rw-r--r-- 1 agriffini agriffini 932 2011-11-25 21:44 algtest2.cpp
-rw-r--r-- 1 agriffini agriffini 1231 2011-11-25 21:45 algtest.cpp
~/x$
The following is the accepted solution (I fixed what is clearly a brainfart of passing the vector of points by value).
// ---------------- algtest.cpp -------------
#include <stdio.h>
#include <math.h>
#include <functional>
#include <algorithm>
#include <vector>
using std::vector;
using std::ptr_fun;
struct Point
{
double x, y;
Point(double x, double y) : x(x), y(y)
{
}
Point operator-(const Point& other) const
{
return Point(x - other.x, y - other.y);
}
};
double magnitude(const Point& a)
{
return sqrt(a.x*a.x + a.y*a.y);
}
double point_distance(const Point& a, const Point& b)
{
return magnitude(b - a);
}
vector<double> adjacent_distances( const vector<Point>& points ) {
if ( points.empty() ) return vector<double>();
vector<double> distances(
1, point_distance( *points.begin(), *points.begin() ) );
std::transform( points.begin(), points.end() - 1,
points.begin() + 1,
std::back_inserter(distances),
ptr_fun( point_distance ) );
return distances;
}
int main()
{
std::vector<Point> points;
for (int i=0; i<1000; i++)
points.push_back(Point(100*cos(i*2*3.141592654/1000),
100*sin(i*2*3.141592654/1000)));
for (int i=0; i<100000; i++)
{
adjacent_distances(points);
}
return 0;
}
Here is instead the explicit loop solution; it requires two include less, one function definition less and the function body is also shorter.
// ----------------------- algtest2.cpp -----------------------
#include <stdio.h>
#include <math.h>
#include <vector>
struct Point
{
double x, y;
Point(double x, double y) : x(x), y(y)
{
}
Point operator-(const Point& other) const
{
return Point(x - other.x, y - other.y);
}
};
double magnitude(const Point& a)
{
return sqrt(a.x*a.x + a.y*a.y);
}
std::vector<double> adjacent_distances(const std::vector<Point>& points)
{
std::vector<double> distances;
if (points.size()) distances.reserve(points.size()-1);
for (int i=1,n=points.size(); i<n; i++)
distances.push_back(magnitude(points[i] - points[i-1]));
return distances;
}
int main()
{
std::vector<Point> points;
for (int i=0; i<1000; i++)
points.push_back(Point(100*cos(i*2*3.141592654/1000),
100*sin(i*2*3.141592654/1000)));
for (int i=0; i<100000; i++)
{
adjacent_distances(points);
}
return 0;
}
Summary:
code size is shorter (algtest2.cpp is less than 76% of algtest.cpp)
compile time is better (algtest2.cpp requires less than 83% of algtest.cpp)
execution time is better (algtest2.cpp runs in less than 85% of algtest.cpp)
So apparently on my system (not hand-picked) I was right on all points except execution speed (the one with "maybe") where to get from slightly slower to substantially faster I had to call reserve on the result array. Even with this optimization the code is of course shorter.
I also think that the fact that this version is more readable is also objective and not an opinion... but I'd be happy to be proven wrong by meeting someone that can understand what the functional thing is doing and that cannot understand what the explicit one is doing instead.
Yes, this can be done, but not easily. I don't think it's worth the effort, unless you really need to avoid the copy.
If you really want to do this, you can try creating your own iterator that iterates over the vector<Point> and a wrapper around Point.
The iterator class will dereference to an instance of the wrapper class. The wrapper class should support operator - or your distance function, and it should store the distance. You should then implement an operator for implicit conversion to double, which will be invoked when adjacent_difference attempts to assign the wrapper to the vector<double>.
I don't have time to go into detail, so if anything is unclear, I'll check back later or someone else can try to explain better. Below is an example of a wrapper that does this.
struct Foo {
Foo(double value) { d = value; }
operator double() { return d; }
double d;
};
Foo sub(const Foo& a, const Foo& b) {
return Foo(a.d - b.d);
}
vector<Foo> values = {1, 2, 3, 5, 8};
vector<double> dist;
adjacent_difference(values.begin(), values.end(), back_inserter(dist), sub);
// dist = {1, 1, 1, 2, 3}
This is maybe a bit dirty, but you could simply add
struct Point {
double x,y,z;
operator double() { return 0.0; }
};
or perhaps
struct Point {
double x,y,z;
operator double() { return sqrt(x*x + y*y + z*z); } // or whatever metric you are using
};
The effect being to set the first distance to 0, or the distance of the first point from the origin. However, I could imagine that you wouldn't want to pollute your Point struct with a rather arbitrary definition for conversion to double - in which case dauphic's wrapper is a cleaner solution.
Since you have no use for the first element returned by adjacent_difference, which is precisely the one giving trouble, you can write your own version of the algorithm, skipping that initial assignment:
template <class InputIterator, class OutputIterator, class BinaryOperation>
OutputIterator my_adjacent_difference(InputIterator first, InputIterator last,
OutputIterator result,
BinaryOperation binary_op)
{
if (first != last)
{
InputIterator prev = first++; // To start
while (first != last)
{
InputIterator val = first++;
*result++ = binary_op(*val, *prev);
prev = val;
}
}
return result;
}
This should work, though you will be missing some STL optimisations.
I like the a) formulation of the problem, b) comparison of the execution times, c) my_adjacent_difference, d) self-comment that my_adjacent_difference may lack built-in optimizations. I agree that the Standard C++ adjacent_difference logic limits the algorithm's application and that the three lines loop-code is a solution, which many would go with. I reuse the idea to apply the algorithm transform and present the version in C++ 11 illustrating lambdas. Regards.
#include <iostream> /* Standard C++ cout, cerr */
#include <vector> /* Standard C++ vector */
#include <algorithm> /* Standard C++ transform */
#include <iterator> /* Standard C++ back_inserter */
#include <cmath> /* Standard C++ sqrt */
#include <stdexcept> /* Standard C++ exception */
using namespace std; /* Standard C++ namespace */
struct Point {double x, y, z;}; // I would define this differently.
int main(int, char*[])
{
try {
const Point points[] = {{0, 0, 0}, {1, 0, 0}, {1, 0, 3}};
vector<double> distances;
transform(points + 1, points + sizeof(points) / sizeof(Point),
points, back_inserter(distances),
[](const Point& p1, const Point& p2)
{
double dx = p2.x - p1.x;
double dy = p2.y - p1.y;
double dz = p2.z - p1.z;
return sqrt(dx * dx + dy * dy + dz * dz);
});
copy(distances.begin(), distances.end(),
ostream_iterator<double>(cout, "\n"));
}
catch(const exception& e) {
cerr << e.what() << endl;
return -1;
}
catch(...) {
cerr << "Unknown exception" << endl;
return -2;
}
return 0;
}
The output:
1
3
Related
Surely the question was asked but I didn't know how to formulate my research to get relevant results.
In my problem, I have a point A and several other points B,C... on a plane.
I want to compare the distances between A-B, A-C, ... and return the closest point for example B.
Except that my way is not very optimized maybe you have better ideas.
here is a small piece of my code that summarizes what I said here is a small piece of my code that summarizes what I said and I replaced the points that are two dimensional vectors by simple int to simplify the explanation.
int A(5);
int B(7);
int C(-3);
int D(9);
int i(1);
int best_dist = A-B;
if((A-C) < best_dist)
{
best_dist = A-C;
i = 2;
}
if((A-D) < best_dist)
{
best_dist = A-D;
i = 3;
}
switch(i){
case 1:
return B;
break;
case 2:
return C;
break;
case 3:
return D;
break;
}
You could put the numbers (/coordinates) into a container (say std::array) and use std::min_element to find the member from which the "from" point (A, in your example) has the smallest absolute distance. E.g.:
#include <algorithm> // std::min_element
#include <array>
#include <cmath> // std::abs
#include <iostream>
int main() {
constexpr int from{5};
constexpr std::array<int, 3> candidates{7, -3, 9};
// consider using an != end() check on the resulting
// iterator if you do not know the container to be non-empty.
int const closest_point_on_plane = *std::min_element(
candidates.begin(), candidates.end(), [](int lhs, int rhs) {
return std::abs(from - lhs) < std::abs(from - rhs);
});
std::cout << closest_point_on_plane; // 7
}
For your actual use case of a plane, you will have to replace the
std::abs(from_point_on_line - to_point_on_line)
distance-on-a-line metric used in the compare lambda with an appropriate
distance(from_point_on_plane, to_point_on_plane)
distance-on-a-plane metric.
I have a void function that takes as arguments iterators to the start and the end of a set of points (Setiterator set_begin, Setiterator set_end),a query point to perform some calculations and a iterator to the beginnig of a set of points ( where I am going to add the results)
void computedist(Setiterator set_begin, Setiterator set_end,
Vector const& query_point, DistanceIterator dist_begin )
{
std::transform(set_begin, set_end, dist_begin, calculation);
}
I have read that with std::transform I can do that calculations over the whole set of points, but I don't know how should I define the calculation to be done, as I am new to C++.
In this case, I want to compute the distance of the points to the query point:
I guess that my calculation should look like this
double calc_dist(double query_point, double point_of_the_set){
double dist;
dist = fabs(query_point - point_of_the_set);
return dist;
But I don't know how should I give the arguments to the function, since I am new to working with iterators.
Thank's!
The flavor of std::transform you are calling expects a UnaryOp function to call, to which it passes '*iterator' by const reference and expects a return value of the iterator::value_type which it writes to *dest.
#include <iostream>
#include <algorithm>
#include <vector>
int main() {
using valtype = int;
std::vector<valtype> v1 { 1, 2, 3, 4, 5 };
std::vector<valtype> v2(v1.size());
std::transform(v1.begin(), v1.end(), v2.begin(),
[] (const valtype& in) { return in * 2; });
for (auto& val : v2)
std::cout << val << '\n';
}
Live demo: http://ideone.com/CUUlvA
I've often seen that you can replace all handwritten/raw loops with stl algorithms. Just to improve my C++ knowledge I've been trying just that.
To populate a std::vector with data I use a for loop and the loops index.
unsigned int buffer_size = (format.getBytesPerSecond() * playlen) / 1000;
// pcm data stored in a 'short type' vector
vector<short> pcm_data;
for (unsigned int i = 0; i < buffer_size; ++i)
{
pcm_data.push_back( static_cast<short>(amplitude * sin((2 * M_PI * i * frequency) / format.SampleRate)) );
}
The above code works fine, as you can see I use the for loops index 'i' for the algorithm to be correct.
How can someone replace that for loop with something from the standard?
The only functions i've seen that almost allow me to do it are std::transform and std::generate, but both of those wouldn't work because I require an index value to increment for the code.
EG:
generate_n(begin(pcm_data), buffer_size, [] ()
{
return static_cast<short>(amplitude * sin((2 * M_PI * i * frequency) / format.SampleRate)); //what is i??
});
transform(begin(pcm_data), end(pcm_data), begin(pcm_data) [] (???)
{
return static_cast<short>(amplitude * sin((2 * M_PI * i * frequency) / format.SampleRate)); //what is i??
});
Or am I simply going too far into the idea of "no raw loops"?
The real solution here would be to define an appropriate
iterator, something like:
class PcmIter : public std::iterator<std::forward_iterator_tag, short>
{
int myIndex;
double myAmplitude;
double myFrequency;
short myValue;
void calculate()
{
myValue = myAmplitude * std::sin( 2 * M_PI * myIndex * frequency );
}
public:
PcmIter( int index, amplitude = 0.0, frequency = 0.0 )
: myIndex( index )
, myAmplitude( amplitude )
, myFrequency( frequency )
{
calculate();
}
bool operator==( PcmIter const& other ) const
{
return myIndex == other.myIndex;
}
bool operator!=( PcmIter const& other ) const
{
return myIndex != other.myIndex;
}
const short& operator*() const
{
return myValue;
}
PcmIter& operator++()
{
++ myIndex;
calculate();
}
PcmIter operator++( int )
{
PcmIter results( *this );
operator++();
return results;
}
};
In practice, I suspect that you could get by with having
operator* return a value, which you calculate at that point,
and not having a myValue member.
To use:
std::vector<short> pcmData(
PcmIter( 0, amplitude, frequency),
PcmIter( buffer_size ) );
(The amplitude and the frequency are irrelevant for the end
iterator, since it will never be dereferenced.)
Ideally, this would be a random_access_iterator, so that the
constructor to vector will calculate the number of elements, and
pre-allocate them. This involves implementing a lot more
functions, however.
If you're courageous, and have to do similar things a lot, you
could consider making the iterator a template, to be
instantiated over the function you're interested in.
And while I've not had a chance to play with them lately, if
you're using Boost, you might consider chaining
a transform_iterator and a counting_iterator. It's still
a bit wordy, but the people who did the iterators at Boost did
the best they could, given the somewhat broken design of STL
iterators.
You can simply use a variable in the scope of your "generate_n" to declare your variable.
unsigned int i = 0;
generate_n(begin(pcm_data), buffer_size, [&] ()
{
return static_cast<short>(amplitude * sin((2 * M_PI * (i++) * frequency) / format.SampleRate)); //what is i??
});
I would recommend counting_iterator in Boost Library. A pair of counting iterators provides you a range of integer. Obviously, there is no underlying container. It provides the integer "lazily". The library provides factory function make_counting_iterator for creating it.
back_insert_iterator (with factory function back_inserter) in Standard Library (header iterator) effectively calls the member push_back of the container.
With these ingredients, you can use transform with the "index".
#include <iostream>
#include <vector>
#include <algorithm>
#include <iterator>
using namespace std;
#include <boost/iterator/counting_iterator.hpp>
int main(int argc, char* argv[])
{
// Create a pair of counting iterators
auto first = boost::make_counting_iterator(0);
auto last = boost::make_counting_iterator(10);
vector<int> vi;
// Construct a vector of a few even number, as an example.
transform(first, last, back_inserter(vi), [](int i){ return 2 * i; });
// Print the result for check
copy(vi.begin(), vi.end(), ostream_iterator<int>{cout, " "});
return 0;
}
The print-out:
0 2 4 6 8 10 12 14 16 18
not necessarily better but a solution with stl:
struct generate_value {
short operator() () const {return amplitude * sin((2 * M_PI * i++ * frequency) / format.SampleRate);}
private:
unsigned i = 0;
};
generate_n(back_inserter(pcm_data), buffer_size, generate_value{});
I see a couple of possibilities I haven't seen mentioned yet. One would start with an iterator for a range of numbers:
template <class T>
class xrange_t {
T start;
T stop;
public:
xrange_t(T start, T stop) : start(start), stop(stop) {}
class iterator : public std::iterator<std::forward_iterator_tag, T> {
T current;
public:
iterator(T t) : current(t) {}
T operator *() { return current; }
iterator &operator++() { ++current; return *this; }
bool operator!=(iterator const &other) const { return current != other.current; }
bool operator==(iterator const &other) const { return current == other.current; }
};
iterator begin() { return iterator(start); }
iterator end() { return iterator(stop); }
};
template <class T>
xrange_t<T> xrange(T start, T stop) {
return xrange_t<T>(start, stop);
}
Then you'd use this with a ranged-for loop to do the real work:
#include "xrange"
for (auto i : xrange(0, buffer_size))
pcm_data.push_back( static_cast<short>(amplitude * sin((2 * M_PI * i * frequency) / format.SampleRate)) );
Another possibility would be to carry out the job in a couple of steps:
std::vector<short> pcm_data(buffer_size);
std::iota(pcm_data.begin(), pcm_data.end(), 0);
std::transform(pcm_data.begin(), pcm_data.end(), pcm_data.begin(),
[](short i) {
return static_cast<short>(amplitude * sin((2 * M_PI * i * frequency) / format.SampleRate)));
}
);
This starts by filling the array with the successive values of i (i.e., the inputs to the function) then transforms each of those inputs to the matching output value.
This has two potential shortcomings though:
If the value of i might exceed the value that can be stored in a short, it might truncate the input value during the initial storage phase. It's not clear whether your use of int for i reflects the possibility that it might have a larger magnitude, or just using int by default.
It traverses the result vector twice. If the vector is large (especially if it's too large to fit in cache) this could be substantially slower.
Have anybody written a C++ STL-compliant algorithm that combines std::transform and std::accumulate into a single pass algorithm supporting both the unary, binary and perhaps even (n-ary!) variant, say std::transformed_accumulate? I want this because I have found this pattern highly reusable in for example linear algebra for example in (l1-)norm calculations. The l1-norm calculates the sum of the absolute values of the elements.
Uhm... My bet is that you can do that by embedding your transformation into the binary predicate, tranform the element and accumulate after the transformation.
struct times2accumulator {
int operator()( int oldvalue, int newvalue ) const {
return oldvalue + 2*newvalue;
}
};
int r = std::accumulate( v.begin(), v.end(), 2, times2accumulator() );
That functor would be equivalent to:
struct times2 {
int operator()( int x ) {
return 2*x;
}
};
std::vector<int> tmp; tmp.reserve( v.size() );
std::transform( v.begin(), v.end(), std::back_inserter(tmp), times2 );
int r = std::accumulate( tmp.begin(), tmp.end(), 0 );
Of course this could be made generic, just pass the transformation functor to a generic base functor:
template <typename Transform>
struct transform_accumulator_t {
Transform t;
transform_accumulator_t( Transform t ) : t(t) {}
int operator()( int oldvalue, int newvalue ) const {
return oldvalue + t(newvalue);
}
};
// syntactic sugar:
template <typename T>
transform_accumulator_t<T> transform_accumulator( T t ) {
return transform_accumulator_t<T>(t);
}
int r = std::accumulate(v.begin(), v.end(), 0, transform_accumulator(times2));
And you could also generalize on the type in the container... or even create a more generic transform_accumulator that takes both an accumulator and a transformation functors and applies them in order. Actual implementation left as an exercise for the reader.
Although it may not exactly fit the original intent, std::inner_product is basically your binary version. You pass it an initial value, two ranges, and two functors, and it applies them as:
T acc = initial_value;
while (begin1 != end1) {
acc = binary_op1(acc, binary_op2(begin1, begin2);
++begin1;
++begin2;
return acc;
So, for your L1 you'd do something on this general order:
norm = std::inner_product(input1.begin(), input1.end(),
input2.begin(), input2.end(),
std::plus<int>(), std::abs);
Only that doesn't quite work -- right now, it's trying to pass std::abs where you really need a binary function that combines the two inputs, but I'm not sure how the two inputs are really supposed to be combined.
std::partial_sum is fairly close to your unary version, except that along with accumulating a result, it (attempts to) write out each intermediate result, not just the final result. To just get the final result, you'd have to write (and pass an instance of) a kind of do-nothing iterator that just holds a single value:
template<class T, class Dist=size_t, class Ptr = T*, class Ref = T&>
class unique_it : public std::iterator<std::random_access_iterator_tag, T, Dist, Ptr, Ref> {
T &value;
public:
unique_it(T &v) : value(v) {}
T &operator*() { return value; }
unique_it &operator++() { return *this; }
unique_it &operator+(size_t) { return *this; }
unique_it &operator++(int) { return *this; }
};
template <class T>
unique_it<T> make_res(T &v) { return unique_it<T>(v); }
With this, your L1 normalization would look something like this:
int main(){
double result=0.0;
double inputs[] = {1, -2, 3, -4, 5, -6};
std::partial_sum(
inputs, inputs+6,
make_res(result),
[](double acc, double v) {return acc + std::abs(v);});
std::cout << result << "\t";
return 0;
}
If you want to use some parallelism, I made a quick version using OpenMP :
template <class T,
class InputIterator,
class MapFunction,
class ReductionFunction>
T MapReduce_n(InputIterator in,
unsigned int size,
T baseval,
MapFunction mapper,
ReductionFunction reducer)
{
T val = baseval;
#pragma omp parallel
{
T map_val = baseval;
#pragma omp for nowait
for (auto i = 0U; i < size; ++i)
{
map_val = reducer(map_val, mapper(*(in + i)));
}
#pragma omp critical
val = reducer(val, map_val);
}
return val;
}
It is fast but there is certainly room for optimisation, especially around for (auto i = 0U; i < size; ++i) I think. (But I couldn't figure how to make an iterator-only version with OpenMP, any help would be appreciated!).
On a quick test with 1000000 elements array, and the computation iterated 1000 times to have a mean value, I made some comparisons.
Version 1 :
for (auto i = 0U; i < size; ++i)
val += std::pow(in[i][0], 2) + std::pow(in[i][1], 2);
score when compiled with:
g++ : 30 seconds
g++ -O3 : 2.6 seconds
Version 2 :
This version is the most optimized for this computation I think. (It gives the best result).
#pragma omp parallel reduction( + : val )
{
double map_val = 0.0;
#pragma omp for
for (int i=0; i < size; ++i)
{
map_val += std::pow(in[i][0], 2) + std::pow(in[i][1], 2);
}
val += map_val;
}
g++ -O3 : 0.2 seconds (it's the best one)
Version 3
This version uses the MapReduce_n function template I shown earlier :
double val = MapReduce_n(in, size, 0.0, [] (fftw_complex val)
{
return std::pow(val[0], 2.0) + std::pow(val[1], 2.0);
}, std::plus<double>());
g++ -O3 : 0.4 seconds, so there is a slight overhead for not using directly the OMP reduce directly. However, it doesn't allows custom operators, so at one point you (sadly) have to trade speed for genericity.
I am surprised noone said how to do this with Boost.Range:
accumulate(v | transformed((int(*)(int))&std::abs), 0);
where v is a Singe Pass Range (ie, any STL container). The abs overload has to be specified, otherwise this would be as elegant as Haskell.
As of C++17 there is also std::transform_reduce, which also has the benefit of being parallelizable.
https://en.cppreference.com/w/cpp/algorithm/transform_reduce
I have an assignment to read a file and output the average test scores.
It is pretty simple but I don't like how the average is done.
average = (test1 + test2 + test3 + test4 + test5) / 5.0;
Is there a way to just have it divide by the number of test scores? I couldn't find anything like this in the book or from google. Something like
average = (test + test + test + test) / ntests;
If you have the values in a vector or an array, just use std::accumulate from <numeric>:
std::vector<double> vec;
// ... fill vec with values (do not use 0; use 0.0)
double average = std::accumulate(vec.begin(), vec.end(), 0.0) / vec.size();
Step 1. Via iteration (if you want to be done) or recursion (if you want to be brave) place all test scores into an array (if you want simplicity and speed) or a linked list (if you want flexibility but slow)
Step 2. Iterate through the array/list until you reach the end; adding the contents of each cell/node as you go. Keep a count of what cell/node you are currently at as you go as well.
Step 3. Take the sum from the first variable and divide it by the second variable that kept track of where you were. This will yield the mean.
Wondering, why no one mentioned boost::accumulators. It is not the shortest of the already posted solutions, but can be more easily extended for more general statistical values. Like standard deviation or higher moments.
#include <iostream>
#include <boost/accumulators/accumulators.hpp>
#include <boost/accumulators/statistics/stats.hpp>
#include <boost/accumulators/statistics/mean.hpp>
#include <algorithm>
#include <vector>
double mean(const std::vector<double>& values) {
namespace bo = boost::accumulators;
if (values.empty()) return 0.;
bo::accumulator_set<double, bo::stats<bo::tag::mean>> acc;
acc=std::for_each(values.begin(), values.end(), acc);
return bo::mean(acc);
}
int main()
{
std::vector<double> test = { 2.,6.,4.,7. };
std::cout << "Mean: " << mean(test) << std::endl;
std::cout << "Mean: " << mean({}) << std::endl;
return 0;
}
Here is my generalization of getting the average of the elements of a container by specifying a lambda function to obtain each value and then add up:
template <typename ForwardIterator, typename F>
double inline averageOf (ForwardIterator first, ForwardIterator last, F function) {
std::vector<typename std::result_of<F(typename ForwardIterator::value_type)>::type> values;
while (first != last) {
values.emplace_back (function(*first));
++first;
}
return static_cast<double>(std::accumulate (values.begin(), values.end(), 0)) / values.size();
}
The client code I tested it with goes like
const std::list<CharmedObserver*> devotees =
charmer->getState<CharmerStateBase>(CHARMER)->getDevotees();
const int averageHitPointsOfDevotees = averageOf (devotees.begin(), devotees.end(),
[](const CharmedObserver* x)->int {return x->getCharmedBeing()->getHitPoints();});
C++11 gives nice solution:
constexpr auto countArguments() -> size_t
{
return 0;
}
template<class T1, class ... Ti>
constexpr auto countArguments(T1, Ti ...xi) -> size_t
{
return 1 + countArguments(xi...);
}
template<class T>
constexpr auto sumAruguments(T x) -> double
{
return x;
}
template<class T1, class ... Ti>
constexpr auto sumAruguments(T1 x1, Ti ...xi) -> double // decltype(x1 + sumAruguments(xi...))
{
return x1 + sumAruguments(xi...);
}
template<class...T>
constexpr auto avarage(T...xi) -> double
{
return sumAruguments(xi...) / countArguments(xi...);
}
I was unable to write it so it auto-deduce return type.
When I tried I get weird result for average(-2).
https://wandbox.org/permlink/brssPjggn64lBGVq
You can also calculate average using variable number of arguments. The principle of this a function that an unknown number of arguments is stored in a stack and we can take them.
double average(int n, ...) // where n - count of argument (number)
{
int *p = &n; // get pointer on list of number in stack
p++; // get first number
double *pp = (double *)p; // transformation of the pointer type
double sum = 0;
for ( int i = 0; i < n; pp++, i++ ) //looking all stack
sum+=(*pp); // summarize
return sum/n; //return average
}
And you can using this function like:
double av1 = average( 5, 3.0, 1.5, 5.0, 1.0, 2.0 );
double av2 = average( 2, 3.0, 1.5 );
But the number of arguments must match with the n.