Search code examples
c++stlaccumulate

C++: average of vector of structs


My struct is a 2D coordinate:

template<typename T>
struct coordinate {
    std::pair<T, T> coords;
    coordinate() : coords({0, 0}) {}
    const T x() const { return coords.first; }
    const T y() const { return coords.second; }

    // functions to set and manipulate x and y

};

I have a std::vector<coordinate<double>> vec and would like to get averages of x and of y coordinates across the vector.

My way is (please don't judge)

double x_ = 0.;
double y_ = 0.;
for (auto v : vec) {
    x_ += v.x();
    y_ += v.y();
}
x_ /= vec.size();
y_ /= vec.size();

I assume there is a more suitable approach? I try to go for std::accumulate, but don't know how to access the struct members in std::accumulate.

I still struggle with C++ so some explanation to your approach would be great.


Solution

  • Like I said, if you want to do arithmetic operations on your type, you likely want to overload the operators. Thus you can do

    #include <numeric>
    #include <vector>
    
    template<typename T>
    struct coordinate {
        std::pair<T, T> coords;
        coordinate() : coords({0, 0}) {}
        coordinate(T x,T y) : coords(x,y) {}
        T x() const { return coords.first; }
        T y() const { return coords.second; }  
    
        coordinate& operator+=(coordinate const& other){
            coords.first += other.coords.first;
            coords.second += other.coords.second;
            return *this;
        }
    
        template<typename D>
        coordinate& operator/=(D divider){
            coords.first /= divider;
            coords.second /= divider;
            return *this;
        }
    };
    
    template<typename T>
    coordinate<T> operator+(coordinate<T> lhs, coordinate<T> const& rhs){
        return lhs += rhs;
    }
    
    template<typename T, typename D>
    coordinate<T> operator/(coordinate<T> lhs, D rhs){
        return lhs /= rhs;
    }
    
    template<typename T>
    coordinate<T> average(std::vector<coordinate<T>> const& vec){
        if (vec.empty()){
            return coordinate<T>{};
        }
        return std::accumulate(cbegin(vec), cend(vec), coordinate<T>{}) / vec.size();
    }
    
    int main()
    {
        std::vector<coordinate<double>> vec{{1,1},{2,0}};
    
        auto avg = average(vec);
    }