14

Assume I have a vector of grades, where the grade is

struct Grade{
   const int grade;
   const int ECTS; // weight
};

Is there a STL/range-v3 algorithm/algorithms that enable me to do this?

I know I could do it with std:: accumulate with some fancy type as an accumulator(that remembers the sum of weights), but I am looking for a simpler alternative if one exists.

Chaurasia
  • 494
  • 1
  • 6
  • 22
NoSenseEtAl
  • 28,205
  • 28
  • 128
  • 277
  • 2
    Constrained numeric algorithms are currently being developed: [P1813](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2019/p1813r0.pdf). They'll enable something like: `ranges::inner_product(grades, grades, 0, {}, {}, &Grade::grade, &Grade::ECTS);` – metalfox Aug 30 '19 at 07:29

2 Answers2

17

The Grade type itself is fancy enough to act as the accumulator type.

auto [grade_sum, ects] = std::accumulate(
    grages.begin(), grades.end(), Grade {0,0}, 
    [] (Grade acc, Grade g) -> Grade {
        return { g.grade*g.ECTS + acc.grade,
                 g.ECTS         + acc.ECTS  };
});
// auto average_grade = grade_sum/ects;

C++17 structured binding can be replaced by std::tie if necessary.

Jarod42
  • 203,559
  • 14
  • 181
  • 302
Tom
  • 3,281
  • 26
  • 33
7

With range-v3, it might be:

auto average = ranges::inner_product(grades, grades, 0, {}, {}, &Grade::grade, &Grade::ECTS)
        / double(ranges::accumulate(grades, 0, {}, &Grade::ECTS));

Demo

Jarod42
  • 203,559
  • 14
  • 181
  • 302
  • 1
    Currently, the compilation time is a show-stopper. https://godbolt.org/z/I1_kGh vs https://godbolt.org/z/eVvMJz or 14448ms (ranges::inner_product) vs 3890ms (std::accumulate) – Porsche9II Sep 16 '19 at 15:48