f



std::transform for std::map

Hi,

it doesn't seem to be possible to use transform for maps.

#include <algorithm>
#include <map>
#include <iterator>
#include <vector>
#include <iostream>

using namespace std;

int doit(int w) {
    return w+1;
}

int main() {
    map<int,int> m;
    vector<int> v;
    m[0]=42;
    v.push_back(42);
    //transform(m.begin(),m.end(),m.begin(),doit); (*)
    transform(v.begin(),v.end(),v.begin(),doit);
    copy(v.begin(),v.end(),ostream_iterator<int>(cout," "));
    cout<<endl;
}

I understand syntactically why the line (*) does not compile. But
conceptually is doesn't make much sense (IMHO) to not be able to use
maps in std::tranform. Even changing doit to

pair<int, int> doit(pair<int, int> w) {
    pair<int,int> result(w);
    w.second++;
    return result;
}

doesn't help. What would be the right way to do it?

Thanks,

Ralf
0
3/16/2009 2:34:51 PM
comp.lang.c++ 49423 articles. 7 followers. Post Follow

7 Replies
730 Views

Similar Articles

[PageSpeed] 43

Ralf Goertz <r_goertz@expires-2006-11-30.arcornews.de> writes:
> it doesn't seem to be possible to use transform for maps.

Yes it is possible:


#include <algorithm>
#include <map>
#include <iterator>
#include <vector>
#include <iostream>

using namespace std;

int doit(std::pair<const int,int>& w) {
    return w.second+1;
}

int main() {
    map<int,int> m;
    map<int,int> o;
    m[0]=42;
    m[3]=33;
    m[6]=66;
    m[2]=22;
    m[4]=44;
    vector<int> v(m.size());
    transform(m.begin(),m.end(),v.begin(),doit);
    copy(v.begin(),v.end(),ostream_iterator<int>(cout," ")); cout<<endl;
    return(0);
}

/*
-*- mode: compilation; default-directory: "/tmp/" -*-
Compilation started at Mon Mar 16 15:45:08

SRC="/tmp/tm.c++" ; EXE="tm" ; g++  -g3 -ggdb3 -o ${EXE} ${SRC} &&  ./${EXE} && echo status = $?
43 23 34 45 67 
status = 0

Compilation finished at Mon Mar 16 15:45:09
 */>

> doesn't help. What would be the right way to do it?

You need to declare the key const in the pair.


-- 
__Pascal Bourguignon__
0
pjb (7869)
3/16/2009 2:46:37 PM
Pascal J. Bourguignon wrote:

> Ralf Goertz <r_goertz@expires-2006-11-30.arcornews.de> writes:
>> it doesn't seem to be possible to use transform for maps.
> 
> Yes it is possible:
> 
> 
> #include <algorithm>
> #include <map>
> #include <iterator>
> #include <vector>
> #include <iostream>
> 
> using namespace std;
> 
> int doit(std::pair<const int,int>& w) {
>     return w.second+1;
> }
> 
> int main() {
>     map<int,int> m;
>     map<int,int> o;
>     m[0]=42;
>     m[3]=33;
>     m[6]=66;
>     m[2]=22;
>     m[4]=44;
>     vector<int> v(m.size());
>     transform(m.begin(),m.end(),v.begin(),doit);
>     copy(v.begin(),v.end(),ostream_iterator<int>(cout," "));
>     cout<<endl; return(0);
> }
> 
> /*
> -*- mode: compilation; default-directory: "/tmp/" -*-
> Compilation started at Mon Mar 16 15:45:08
> 
> SRC="/tmp/tm.c++" ; EXE="tm" ; g++  -g3 -ggdb3 -o ${EXE} ${SRC} && 
> ./${EXE} && echo status = $? 43 23 34 45 67
> status = 0
> 
> Compilation finished at Mon Mar 16 15:45:09
>  */>
> 
>> doesn't help. What would be the right way to do it?
> 
> You need to declare the key const in the pair.

Okay, thanks. But can I also do it *in place* (like I did it with the
vector in the OP). 
 
0
3/16/2009 2:57:22 PM
On Mar 16, 7:46=A0am, p...@informatimago.com (Pascal J. Bourguignon)
wrote:
> Ralf Goertz <r_goe...@expires-2006-11-30.arcornews.de> writes:
> > it doesn't seem to be possible to use transform for maps.
>
> Yes it is possible:
>
> #include <algorithm>
> #include <map>
> #include <iterator>
> #include <vector>
> #include <iostream>
>
> using namespace std;
>
> int doit(std::pair<const int,int>& w) {
> =A0 =A0 return w.second+1;
>
> }
>
> int main() {
> =A0 =A0 map<int,int> m;
> =A0 =A0 map<int,int> o;
> =A0 =A0 m[0]=3D42;
> =A0 =A0 m[3]=3D33;
> =A0 =A0 m[6]=3D66;
> =A0 =A0 m[2]=3D22;
> =A0 =A0 m[4]=3D44;
> =A0 =A0 vector<int> v(m.size());
> =A0 =A0 transform(m.begin(),m.end(),v.begin(),doit);
> =A0 =A0 copy(v.begin(),v.end(),ostream_iterator<int>(cout," ")); cout<<en=
dl;
> =A0 =A0 return(0);
>
> }
>
> /*
> -*- mode: compilation; default-directory: "/tmp/" -*-
> Compilation started at Mon Mar 16 15:45:08
>
> SRC=3D"/tmp/tm.c++" ; EXE=3D"tm" ; g++ =A0-g3 -ggdb3 -o ${EXE} ${SRC} && =
=A0./${EXE} && echo status =3D $?
> 43 23 34 45 67
> status =3D 0
>
> Compilation finished at Mon Mar 16 15:45:09
> =A0*/>
>
> > doesn't help. What would be the right way to do it?
>
> You need to declare the key const in the pair.


Even better would be:

typedef std::map<int, int> intmap;

int doit(intmap::value_type w)
{
    return w.second + 1;
}


0
redfloyd (276)
3/16/2009 4:00:01 PM
On Mar 16, 3:34 pm, Ralf Goertz
<r_goe...@expires-2006-11-30.arcornews.de> wrote:
> it doesn't seem to be possible to use transform for maps.

That's because maps aren't really containers, in the usual
sense.

> #include <algorithm>
> #include <map>
> #include <iterator>
> #include <vector>
> #include <iostream>

> using namespace std;
>
> int doit(int w) {
>     return w+1;
> }

> int main() {
>     map<int,int> m;
>     vector<int> v;
>     m[0]=3D42;
>     v.push_back(42);
>     //transform(m.begin(),m.end(),m.begin(),doit); (*)
>     transform(v.begin(),v.end(),v.begin(),doit);
>     copy(v.begin(),v.end(),ostream_iterator<int>(cout," "));
>     cout<<endl;
> }

> I understand syntactically why the line (*) does not compile.
> But conceptually is doesn't make much sense (IMHO) to not be
> able to use maps in std::tranform. Even changing doit to

> pair<int, int> doit(pair<int, int> w) {
>     pair<int,int> result(w);
>     w.second++;
>     return result;
> }

> doesn't help. What would be the right way to do it?

Probably using an iterator adaptor or an iterator facade from
Boost.  Basically, what you want is an iterator which only
"shows" the second element of the pair.

--
James Kanze (GABI Software)             email:james.kanze@gmail.com
Conseils en informatique orient=E9e objet/
                   Beratung in objektorientierter Datenverarbeitung
9 place S=E9mard, 78210 St.-Cyr-l'=C9cole, France, +33 (0)1 30 23 00 34
0
james.kanze (9769)
3/17/2009 12:16:11 PM
James Kanze wrote:
> On Mar 16, 3:34 pm, Ralf Goertz
> <r_goe...@expires-2006-11-30.arcornews.de> wrote:
> 
>> doesn't help. What would be the right way to do it?
> 
> Probably using an iterator adaptor or an iterator facade from
> Boost.  Basically, what you want is an iterator which only
> "shows" the second element of the pair.
> 

What about using std::for_each? map<K,V>::value_type is typedef'ed as
std::pair<const K, V>, meaning that as long as you have a non-const map,
the iterator you get from begin() will allow you to change the value. I
think the following does what the OP wants.

#include <iostream>
#include <map>

typedef std::map<int,int> intmap;

void doit( intmap::value_type &item ){
    // Modify the second element (value) of the pair
    item.second++;
}

int main(int argc, char* argv[])
{
    intmap m;

    m[6*9] = 42;
    m[2] = 4;
    m[3] = 9;

    std::for_each(m.begin(),m.end(),doit);

    // Here m[54] = 43, m[2] = 5, m[3] = 10

    return EXIT_SUCCESS;
}
0
3/17/2009 5:30:40 PM
On Mar 17, 6:30 pm, Joe <clcppnos...@gmail.com> wrote:
> James Kanze wrote:
> > On Mar 16, 3:34 pm, Ralf Goertz
> > <r_goe...@expires-2006-11-30.arcornews.de> wrote:

> >> doesn't help. What would be the right way to do it?

> > Probably using an iterator adaptor or an iterator facade
> > from Boost.  Basically, what you want is an iterator which
> > only "shows" the second element of the pair.

> What about using std::for_each? map<K,V>::value_type is
> typedef'ed as std::pair<const K, V>, meaning that as long as
> you have a non-const map, the iterator you get from begin()
> will allow you to change the value.

Sure, but transform and the special iterators express the intent
a lot better.  He wants to iterate over the mapped objects, and
transform them.

--
James Kanze (GABI Software)             email:james.kanze@gmail.com
Conseils en informatique orient=E9e objet/
                   Beratung in objektorientierter Datenverarbeitung
9 place S=E9mard, 78210 St.-Cyr-l'=C9cole, France, +33 (0)1 30 23 00 34
0
james.kanze (9769)
3/17/2009 10:46:50 PM
James Kanze wrote:

> On Mar 17, 6:30 pm, Joe <clcppnos...@gmail.com> wrote:
>> James Kanze wrote:
>> > On Mar 16, 3:34 pm, Ralf Goertz
>> > <r_goe...@expires-2006-11-30.arcornews.de> wrote:
> 
>> >> doesn't help. What would be the right way to do it?
> 
>> > Probably using an iterator adaptor or an iterator facade
>> > from Boost.  Basically, what you want is an iterator which
>> > only "shows" the second element of the pair.
> 
>> What about using std::for_each? map<K,V>::value_type is
>> typedef'ed as std::pair<const K, V>, meaning that as long as
>> you have a non-const map, the iterator you get from begin()
>> will allow you to change the value.
> 
> Sure, but transform and the special iterators express the intent
> a lot better.  He wants to iterate over the mapped objects, and
> transform them.

Yes, that was the reasoning. I will check the special iterator approach
but I'm also happy with the for_each solution.

Thanks,

Ralf
0
3/18/2009 9:09:06 AM
Reply: