-1

I'm aware this has been asked on here before:

stl::multimap - how do i get groups of data?

but the answer:

pair<Iter, Iter> range = my_multimap.equal_range("Group1");
int total = accumulate(range.first, range.second, 0);

does not compile for me, when I do:

pair<multimap<int32_t, float>::iterator, multimap<int32_t, float>::iterator> range = multimap.equal_range(an_int);
float total = accumulate(range.first, range.second, 0);

This was on GCC 4.8

Could anyone confirm whether they can compile this/offer the correct answer?

Community
  • 1
  • 1
user997112
  • 29,025
  • 43
  • 182
  • 361

2 Answers2

5

There are four problems with this code:

  1. You have too many closing angle brackets.
  2. Your multimap probably shouldn't be named multimap. (Although this might not cause a compile error, it's pretty obvious that you shouldn't do it.)
  3. Dereferencing a multimap iterator gives a key-value pair, rather than just the value. So of course you can't sum these with std::accumulate directly.
  4. Even if you did this with a multiset instead of a multimap, so #3 wouldn't apply, passing 0 as the initial value will cause all the floats to be truncated as it would deduce type int for the accumulator... so you would probably get the wrong answer.

It looks like you're stuck in 2003, since you actually wrote out the return type of equal_range, so I guess no lambdas or range-for-loops for you.

pair<multimap<int32_t, float>::iterator,
     multimap<int32_t, float>::iterator> range = M.equal_range(an_int);
float total = 0;
for (multimap<int32_t, float>::iterator I = range.first; I != range.second; ++I) {
    total += I->second;
}

Or avoid equal_range and that nasty declaration altogether...

float total = 0;
for (multimap<int32_t, float>::iterator I = M.lower_bound(an_int);
     I != M.end() && I->first == an_int;
     ++I) {
    total += I->second;
}

Edit: Okay, so you do have C++11 support. So you can do this:

auto range = M.equal_range(an_int);
float total = accumulate(range.first, range.second, 0.0,
                         [](float x, pair<int32_t, float> y) { return x + y.second; });

(Note: If you have C++14 support, you can even replace pair<int32_t, float> by auto in the lambda.)

Brian Bi
  • 111,498
  • 10
  • 176
  • 312
3

I believe gcc 4.8 already supported the C++11 redefinition of auto1 and lambdas, so you should be able to use:

auto range = multimap.equal_range(an_int);
std::cout << std::accumulate(range.first, range.second, 0, 
    [](int a, std::pair<int32, float> b) { return a + b.second; });

[of course, you need to specify the name of your multimap object, where this has multimap.]

As an aside, since you're expecting the result as a float, you may want to change your initial value to a float, so the accumulation is done on floats, not ints:

std::cout << std::accumulate(range.first, range.second, 
    0.0f,
    [](float a, std::pair<int32, float> b) { return a + b.second; });

1. with the -std=C++0x flag.

Jerry Coffin
  • 476,176
  • 80
  • 629
  • 1,111