On 24 Jul 2003 14:16:41 -0700,
paulmg@digitalbrain.com (Paul MG)
wrote:
[color=blue]
>Hi
>
>Is there a simple general way of getting the keys out of a map? Or a vector of
>pairs?
>
>My problem seems to be that the pair<> type returned by iterating through either
>has no methods to bind to to get the .first or .second elements. That seems to
>me to be a major oversight - so I am assuming I must be making one!
>
>For instance, imagine I want to use eg accumulate, to add up all the keys in a
>map:
>
>
> template<class A, class B>
> struct FirstOfPair : public unary_function<const pair<A, B>, A> {
> A operator()(const pair<A, B>& p) { return p.first; }
> };
>
> template<class A, class B>
> struct AccumulatePairFirsts : public binary_function<A, const pair<A, B>, A> {
> A operator()(A a, const pair<A, B>& p) { return a + FirstOfPair<A,B>()(p); }
> };
>
> int sumKeys(const map<int, string>& m) {
> return accumulate(m.begin(), m.end(), 0,
> AccumulatePairFirsts<int, string>());
> }
>
>
>This is pretty horrendous! It took me about 20 goes to get this all right. Also
>I am not happy that I had to define AccumulatePairFirsts - couldnt I bind (or
>compose?) with plus<int>() here?
>
>Calling any gurus, please help!
>
>I have a not-totally-weak functional background btw; I just often find it hard
>to see how to do simple things using C++'s 'way'.[/color]
If you must use algorithms, then you should either use iterator
adaptors or lambda functions. e.g.
To write an iterator adaptor that projects an iterator onto the first
member of a pair (or use the projection iterator with a suitable
functor):
http://www.boost.org/libs/utility/iterator_adaptors.htm
Using boost.lambda:
http://www.boost.org/libs/lambda/doc/index.html
#include <map>
#include <string>
#include <numeric>
#include <iostream>
#include <boost/lambda/lambda.hpp>
#include <boost/lambda/bind.hpp>
int main()
{
using namespace boost::lambda;
typedef std::map<int, std::string> m_t;
typedef m_t::value_type pair_t;
m_t m;
m[4] = "Foo";
m[2] = "Bar";
int result = std::accumulate(
m.begin(),
m.end(),
0,
_1 + bind(&pair_t::first, _2)
);
std::cout << result << '\n';
}
Without a toolkit like boost.lambda handy, the for loop definitely
wins in cases like this, and even with boost.lambda, the increase in
compile times might not be worth it.
Tom