std::transform for std::map

R

Ralf Goertz

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
 
P

Pascal J. Bourguignon

Ralf Goertz said:
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.
 
R

Ralf Goertz

Pascal said:
Ralf Goertz said:
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).
 
R

red floyd

Ralf Goertz said:
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.


Even better would be:

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

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

James Kanze

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]=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?

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.
 
J

James Kanze

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.
 
R

Ralf Goertz

James said:
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
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,769
Messages
2,569,579
Members
45,053
Latest member
BrodieSola

Latest Threads

Top