Jump to content

Adding all values in a std::map


Guest LilleCarl_

Recommended Posts

Lets pretend i have a std::map looking like this:

guid healing damage

1 1000 1000

2 1523 3456

3 100 2345

Lets say i want to get all damage values in to one variable. (1000+3456+2345)

Right now im running this:

   for (std::map<uint64, DamageHealData*>::iterator itr = m_DamagersAndHealers.begin(); itr != m_DamagersAndHealers.end(); ++itr)
   {
       if (itr->second->damage > 0)
           victimHealth += itr->second->damage;
   }

Could this be done in any other way? Like "faster" or smth? ^^,

Link to comment
Share on other sites

A for loop such as yours is often used; it's just fine. If you really want a one-liner, you could use 'accumulate' in this case (it's in the <numeric> header).

Assuming you just have a vector of integers, you could write your sum like this:

victimHealth = std::accumulate( m_DamagersAndHealers.begin(), m_DamagersAndHealers_int.end(), 0 );

The 0 you see is an initial value you choose. It's to make sure you have a predictable value in case your range is empty :)

But, and there's the problem already: you do not have a vector of simple integers. You have structs with members. Fortunately there is a second accumulate, which takes a binary function to serve as the operator used to accumulate the elements. So your code could be written like this:

// some helper function...
static uint64 add_damage( uint64 sum, DamageHealData* element )
{
  if ( element->damage > 0 )
    return sum + element->damage;
}

// ... 
victimHealth = std::accumulate( m_DamagersAndHealers.begin(), m_DamagersAndHealers_int.end(), 0, add_damage );

But as you can see, that's hardy shorter, and I doubt the average person thinks it is simpler to read and understand. So my advice: feel free to stick with a simple for loop :)

Oh, and a remark: since you're not going to change anything in your vector here, start using const iterators :P

std::map<uint64, DamageHealData*>::const_iterator itr

Edit: damn, I now see your structs are not in a vector but in a map... well, simple exercise for the reader to adjust the code. It's almost the same really ;)

Link to comment
Share on other sites

A for loop such as yours is often used; it's just fine. If you really want a one-liner, you could use 'accumulate' in this case (it's in the <numeric> header).

Assuming you just have a vector of integers, you could write your sum like this:

victimHealth = std::accumulate( m_DamagersAndHealers.begin(), m_DamagersAndHealers_int.end(), 0 );

The 0 you see is an initial value you choose. It's to make sure you have a predictable value in case your range is empty :)

But, and there's the problem already: you do not have a vector of simple integers. You have structs with members. Fortunately there is a second accumulate, which takes a binary function to serve as the operator used to accumulate the elements. So your code could be written like this:

// some helper function...
static uint64 add_damage( uint64 sum, DamageHealData* element )
{
  if ( element->damage > 0 )
    return sum + element->damage;
}

// ... 
victimHealth = std::accumulate( m_DamagersAndHealers.begin(), m_DamagersAndHealers_int.end(), 0, add_damage );

But as you can see, that's hardy shorter, and I doubt the average person thinks it is simpler to read and understand. So my advice: feel free to stick with a simple for loop :)

Oh, and a remark: since you're not going to change anything in your vector here, start using const iterators :P

std::map<uint64, DamageHealData*>::const_iterator itr

Edit: damn, I now see your structs are not in a vector but in a map... well, simple exercise for the reader to adjust the code. It's almost the same really ;)

I guess that is exactly what i was looking for, but is this faster then using the loop?

EDIT: Im also thinking about splitting this damagehealdata map into 2 maps instead. One for healing and one for damage, because they do no interfer with eachother. I guess that would be better, then i could skip some checks as well (if damage > 0) for example? What do you think? =) Im going to approach accumulate now :D

Going for this now:

void Player::Damaged(uint64 guid,uint32 damage)
{
   if (m_Damagers[guid])
   {
       m_Damagers[guid] += damage;
   }
   else
   {
       m_Damagers.insert(guid,damage);
   }
}

Lets see if it works (Brackets are auto added with visual assist x, will remove etc...)

I love editing posts!

void Player::Damaged(uint64 guid,uint32 damage)
{
   if (m_Damagers[guid])
       m_Damagers[guid] += damage;
   else
       m_Damagers.insert(std::pair<uint64,uint32>(guid,damage));
}

void Player::Healed(uint64 guid,uint32 healing)
{
   if (m_Healers[guid])
       m_Healers[guid] += healing;
   else
       m_Healers.insert(std::pair<uint64,uint32>(guid,healing));
}

Will test in a few :)

Link to comment
Share on other sites

Ill post again now instead of editing again, std::accumulate was not defined, using VS 2008. Is this a c++11 addition?

Edit: Included <numeric> and got this! :o

2>C:\\Program Files (x86)\\Microsoft Visual Studio 9.0\\VC\\include\\numeric(25) : error C2784: 'std::_Deque_iterator<_Ty,_Alloc,_Secure_validation> std::operator +(_Deque_iterator<_Ty,_Alloc,_Secure_validation>::difference_type,std::_Deque_iterator<_Ty,_Alloc,_Secure_validation>)' : could not deduce template argument for 'std::_Deque_iterator<_Ty,_Alloc,_Secure_validation>' from 'std::pair<_Ty1,_Ty2>'

2> with

2> [

2> _Ty1=const uint64,

2> _Ty2=uint32

2> ]

2> C:\\Program Files (x86)\\Microsoft Visual Studio 9.0\\VC\\include\\deque(456) : see declaration of 'std::operator +'

2> C:\\Program Files (x86)\\Microsoft Visual Studio 9.0\\VC\\include\\numeric(33) : see reference to function template instantiation '_Ty std::_Accumulate<_InIt,_Ty>(_InIt,_InIt,_Ty)' being compiled

2> with

2> [

2> _Ty=int,

2> _InIt=std::_Tree<std::_Tmap_traits<uint64,uint32,std::less<uint64>,std::allocator<std::pair<const uint64,uint32>>,false>>::iterator

2> ]

2> ..\\..\\src\\game\\Player.cpp(20865) : see reference to function template instantiation '_Ty std::accumulate<std::_Tree<_Traits>::iterator,int>(_InIt,_InIt,_Ty)' being compiled

2> with

2> [

2> _Ty=int,

2> _Traits=std::_Tmap_traits<uint64,uint32,std::less<uint64>,std::allocator<std::pair<const uint64,uint32>>,false>,

2> _InIt=std::_Tree<std::_Tmap_traits<uint64,uint32,std::less<uint64>,std::allocator<std::pair<const uint64,uint32>>,false>>::iterator

2> ]

2>C:\\Program Files (x86)\\Microsoft Visual Studio 9.0\\VC\\include\\numeric(25) : error C2784: 'std::_Deque_const_iterator<_Ty,_Alloc,_Secure_validation> std::operator +(_Deque_const_iterator<_Ty,_Alloc,_Secure_validation>::difference_type,std::_Deque_const_iterator<_Ty,_Alloc,_Secure_validation>)' : could not deduce template argument for 'std::_Deque_const_iterator<_Ty,_Alloc,_Secure_validation>' from 'std::pair<_Ty1,_Ty2>'

2> with

2> [

2> _Ty1=const uint64,

2> _Ty2=uint32

2> ]

2> C:\\Program Files (x86)\\Microsoft Visual Studio 9.0\\VC\\include\\deque(329) : see declaration of 'std::operator +'

2>C:\\Program Files (x86)\\Microsoft Visual Studio 9.0\\VC\\include\\numeric(25) : error C2784: 'std::basic_string<_Elem,_Traits,_Alloc> std::operator +(const std::basic_string<_Elem,_Traits,_Alloc> &,const _Elem)' : could not deduce template argument for 'const std::basic_string<_Elem,_Traits,_Alloc> &' from 'int'

2> C:\\Program Files (x86)\\Microsoft Visual Studio 9.0\\VC\\include\\string(60) : see declaration of 'std::operator +'

2>C:\\Program Files (x86)\\Microsoft Visual Studio 9.0\\VC\\include\\numeric(25) : error C2784: 'std::basic_string<_Elem,_Traits,_Alloc> std::operator +(const std::basic_string<_Elem,_Traits,_Alloc> &,const _Elem *)' : could not deduce template argument for 'const std::basic_string<_Elem,_Traits,_Alloc> &' from 'int'

2> C:\\Program Files (x86)\\Microsoft Visual Studio 9.0\\VC\\include\\string(50) : see declaration of 'std::operator +'

2>C:\\Program Files (x86)\\Microsoft Visual Studio 9.0\\VC\\include\\numeric(25) : error C2784: 'std::basic_string<_Elem,_Traits,_Alloc> std::operator +(const _Elem,const std::basic_string<_Elem,_Traits,_Alloc> &)' : could not deduce template argument for 'const std::basic_string<_Elem,_Traits,_Alloc> &' from 'std::pair<_Ty1,_Ty2>'

2> with

2> [

2> _Ty1=const uint64,

2> _Ty2=uint32

2> ]

2> C:\\Program Files (x86)\\Microsoft Visual Studio 9.0\\VC\\include\\string(40) : see declaration of 'std::operator +'

2>C:\\Program Files (x86)\\Microsoft Visual Studio 9.0\\VC\\include\\numeric(25) : error C2784: 'std::basic_string<_Elem,_Traits,_Alloc> std::operator +(const _Elem *,const std::basic_string<_Elem,_Traits,_Alloc> &)' : could not deduce template argument for 'const _Elem *' from 'int'

2> C:\\Program Files (x86)\\Microsoft Visual Studio 9.0\\VC\\include\\string(30) : see declaration of 'std::operator +'

2>C:\\Program Files (x86)\\Microsoft Visual Studio 9.0\\VC\\include\\numeric(25) : error C2784: 'std::basic_string<_Elem,_Traits,_Alloc> std::operator +(const std::basic_string<_Elem,_Traits,_Alloc> &,const std::basic_string<_Elem,_Traits,_Alloc> &)' : could not deduce template argument for 'const std::basic_string<_Elem,_Traits,_Alloc> &' from 'int'

2> C:\\Program Files (x86)\\Microsoft Visual Studio 9.0\\VC\\include\\string(20) : see declaration of 'std::operator +'

2>C:\\Program Files (x86)\\Microsoft Visual Studio 9.0\\VC\\include\\numeric(25) : error C2784: 'std::_Vb_iterator<_Sizet,_Difft,_MycontTy> std::operator +(_Difft,std::_Vb_iterator<_Sizet,_Difft,_MycontTy>)' : could not deduce template argument for 'std::_Vb_iterator<_Sizet,_Difft,_MycontTy>' from 'std::pair<_Ty1,_Ty2>'

2> with

2> [

2> _Ty1=const uint64,

2> _Ty2=uint32

2> ]

2> C:\\Program Files (x86)\\Microsoft Visual Studio 9.0\\VC\\include\\vector(1854) : see declaration of 'std::operator +'

2>C:\\Program Files (x86)\\Microsoft Visual Studio 9.0\\VC\\include\\numeric(25) : error C2784: 'std::_Vb_const_iterator<_Sizet,_Difft,_MycontTy> std::operator +(_Difft,std::_Vb_const_iterator<_Sizet,_Difft,_MycontTy>)' : could not deduce template argument for 'std::_Vb_const_iterator<_Sizet,_Difft,_MycontTy>' from 'std::pair<_Ty1,_Ty2>'

2> with

2> [

2> _Ty1=const uint64,

2> _Ty2=uint32

2> ]

2> C:\\Program Files (x86)\\Microsoft Visual Studio 9.0\\VC\\include\\vector(1743) : see declaration of 'std::operator +'

2>C:\\Program Files (x86)\\Microsoft Visual Studio 9.0\\VC\\include\\numeric(25) : error C2784: 'std::_Vector_iterator<_Ty,_Alloc> std::operator +(_Vector_iterator<_Ty,_Alloc>::difference_type,std::_Vector_iterator<_Ty,_Alloc>)' : could not deduce template argument for 'std::_Vector_iterator<_Ty,_Alloc>' from 'std::pair<_Ty1,_Ty2>'

2> with

2> [

2> _Ty1=const uint64,

2> _Ty2=uint32

2> ]

2> C:\\Program Files (x86)\\Microsoft Visual Studio 9.0\\VC\\include\\vector(409) : see declaration of 'std::operator +'

2>C:\\Program Files (x86)\\Microsoft Visual Studio 9.0\\VC\\include\\numeric(25) : error C2784: 'std::_Vector_const_iterator<_Ty,_Alloc> std::operator +(_Vector_const_iterator<_Ty,_Alloc>::difference_type,std::_Vector_const_iterator<_Ty,_Alloc>)' : could not deduce template argument for 'std::_Vector_const_iterator<_Ty,_Alloc>' from 'std::pair<_Ty1,_Ty2>'

2> with

2> [

2> _Ty1=const uint64,

2> _Ty2=uint32

2> ]

2> C:\\Program Files (x86)\\Microsoft Visual Studio 9.0\\VC\\include\\vector(277) : see declaration of 'std::operator +'

2>C:\\Program Files (x86)\\Microsoft Visual Studio 9.0\\VC\\include\\numeric(25) : error C2784: 'std::_String_iterator<_Elem,_Traits,_Alloc> std::operator +(_String_iterator<_Elem,_Traits,_Alloc>::difference_type,std::_String_iterator<_Elem,_Traits,_Alloc>)' : could not deduce template argument for 'std::_String_iterator<_Elem,_Traits,_Alloc>' from 'std::pair<_Ty1,_Ty2>'

2> with

2> [

2> _Ty1=const uint64,

2> _Ty2=uint32

2> ]

2> C:\\Program Files (x86)\\Microsoft Visual Studio 9.0\\VC\\include\\xstring(440) : see declaration of 'std::operator +'

2>C:\\Program Files (x86)\\Microsoft Visual Studio 9.0\\VC\\include\\numeric(25) : error C2784: 'std::_String_const_iterator<_Elem,_Traits,_Alloc> std::operator +(_String_const_iterator<_Elem,_Traits,_Alloc>::difference_type,std::_String_const_iterator<_Elem,_Traits,_Alloc>)' : could not deduce template argument for 'std::_String_const_iterator<_Elem,_Traits,_Alloc>' from 'std::pair<_Ty1,_Ty2>'

2> with

2> [

2> _Ty1=const uint64,

2> _Ty2=uint32

2> ]

2> C:\\Program Files (x86)\\Microsoft Visual Studio 9.0\\VC\\include\\xstring(300) : see declaration of 'std::operator +'

2>C:\\Program Files (x86)\\Microsoft Visual Studio 9.0\\VC\\include\\numeric(25) : error C2784: 'std::reverse_iterator<_RanIt> std::operator +(_Diff,const std::reverse_iterator<_RanIt> &)' : could not deduce template argument for 'const std::reverse_iterator<_RanIt> &' from 'std::pair<_Ty1,_Ty2>'

2> with

2> [

2> _Ty1=const uint64,

2> _Ty2=uint32

2> ]

2> C:\\Program Files (x86)\\Microsoft Visual Studio 9.0\\VC\\include\\xutility(2203) : see declaration of 'std::operator +'

2>C:\\Program Files (x86)\\Microsoft Visual Studio 9.0\\VC\\include\\numeric(25) : error C2784: 'std::_Revranit<_RanIt,_Base> std::operator +(_Diff,const std::_Revranit<_RanIt,_Base> &)' : could not deduce template argument for 'const std::_Revranit<_RanIt,_Base> &' from 'std::pair<_Ty1,_Ty2>'

2> with

2> [

2> _Ty1=const uint64,

2> _Ty2=uint32

2> ]

2> C:\\Program Files (x86)\\Microsoft Visual Studio 9.0\\VC\\include\\xutility(2003) : see declaration of 'std::operator +'

2>C:\\Program Files (x86)\\Microsoft Visual Studio 9.0\\VC\\include\\numeric(25) : error C2677: binary '+' : no global operator found which takes type 'std::pair<_Ty1,_Ty2>' (or there is no acceptable conversion)

2> with

2> [

2> _Ty1=const uint64,

2> _Ty2=uint32

2> ]

Link to comment
Share on other sites

Ill post again now instead of editing again, std::accumulate was not defined, using VS 2008. Is this a c++11 addition?

No, it's not. As you found out, you need to include <numeric> for that to work (and I even warned you in my post! :P)

Edit: Included <numeric> and got this! :o

...

Ah the joy of template related errors! Yeah, they're horrible.

Without some code I can't really see what's wrong, but I see a few mentions of 'std::operator +' and 'could not deduce template argument for...', so I'm guessing you went with the first version of accumulate, that uses the default of adding the elements up. Not the second version, where the 'adding' operation can be specified as a parameter (see my examples).

Link to comment
Share on other sites

Ill post again now instead of editing again, std::accumulate was not defined, using VS 2008. Is this a c++11 addition?

No, it's not. As you found out, you need to include <numeric> for that to work (and I even warned you in my post! :P)

Edit: Included <numeric> and got this! :o

...

Ah the joy of template related errors! Yeah, they're horrible.

Without some code I can't really see what's wrong, but I see a few mentions of 'std::operator +' and 'could not deduce template argument for...', so I'm guessing you went with the first version of accumulate, that uses the default of adding the elements up. Not the second version, where the 'adding' operation can be specified as a parameter (see my examples).

Working now, sry for not reporting ^^, Im using this function in accumulate:

uint32 pair_adder(uint32 n, const std::map<uint64, uint32>::value_type & p) { return n + p.second; }

(I splitted the damage and healing to different maps)

Link to comment
Share on other sites

Archived

This topic is now archived and is closed to further replies.

×
×
  • Create New...

Important Information

We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue. Privacy Policy Terms of Use