I have a question. Is there any generic algorithm or solution to
access the keys or values
of a map? I frequently face to such problem and I usually write a
function to copy
the keys/values of a map into a container let say a vector.
Many thanks, in advance, for your help.
I've written a utility roughly like this:
#include <string>
#include <algorithm>
#include <iostream>
#include <list>
#include <map>
#include <iterator>
namespace {
template <typename T1, typename T2>
const T1& take_first(const typename std::map<T1,T2>::value_type& pair) {
return pair.first;
}
}
template <typename T1, typename T2>
std::list<T1> keys(const std::map<T1,T2>& in) {
std::list<T1> klist(in.size());
std::transform(in.begin(), in.end(), klist.begin(), take_first<T1,T2>);
return klist;
}
int main() {
std::map<std::string, int> map;
map["test"] = 0;
map["test2"] = 0;
const std::list<std::string>& keys = ::keys(map);
std::copy(keys.begin(), keys.end(),
std::ostream_iterator<std::string>(std::cout, "\n"));
return 0;
}
Although this isn't exactly ideal, and would be a nice place to use a
lambda function in C++0x too.
There's a few annoying things about this though, the function take_first
has to live inside the anonymous namespace because it's not legal to
write the following, which given the absence of lambda functions would
be cleaner in my view:
template <typename T1, typename T2>
std::list<T1> keys(const std::map<T1,T2>& in) {
struct {
const T1& operator()(const typename std::map<T1,T2>::value_type&
pair) {
return pair.first;
}
} take_first;
std::list<T1> klist(in.size());
std::transform(in.begin(), in.end(), klist.begin(), take_first);
return klist;
}
I also never got type deduction for the function pointer argument to
std::transform to work, which I kind of expected it would, although
that's not exactly a problem.
Alan
Hi Alan
Thank you for your code. It is really good. It is better than my code
and I definitely will use it.
So, there is no pre-built generic algorithm for doing this.
Thanks again,
-- Saeed Amrollahi
#include <string>
#include <iterator>
#include <boost/foreach.hpp>
#include <iostream>
#include <list>
#include <map>
typedef std::map<std::wstring,std::wstring> MyMapType;
typedef std::pair<std::wstring,std::wstring> MapPairType;
MyMapType MyMap;
template<typename U>
std::list<typename U::key_type> getKeys(U const &m)
{
typedef std::pair<typename U::key_type,typename U::mapped_type>
PairType;
std::list<typename U::key_type> tempList;
BOOST_FOREACH(PairType const &i,m)
tempList.push_back(i.first);
return tempList;
}
int main()
{
MyMap[L"one"] = L"Hello World";
MyMap[L"two"] = L"Another string";
std::list<std::wstring> myList = getKeys(MyMap);
BOOST_FOREACH(std::wstring &i,myList)
std::wcout << i << L"\n";
return 0;
}
Thank you.
What exactly do you want? You just want to access a map's current
contents? Then iterate over the contents, like so:
for (map<int, int>::iterator x = someMap.begin(); x != someMap.end(); +
+x)
{
int const& key = x->first;
int& value = x->second;
//do whatever with this (key, value) pair
}
Do you want to create a new container which holds all of the keys? Or
holds all of the values? Then iterate over the contents and build the
new container, like so:
map<int, int> someMap;
vector<int> listOfKeys;
for (map<int, int>::iterator x = someMap.begin(); x != someMap.end(); +
+x)
listOfKeys.push_back(x->first);
I would not write a separate function for a two liner using very basic
standard library stuff like this. Wrapping such basic usage for ease
of use does not result in ease of use. It results in only obfuscation.
This will work:
template <typename T1, typename T2>
std::list<T1> keys(const std::map<T1,T2>& in) {
struct take_first{
static const T1& op(const typename std::map<T1,T2>::value_type&
pair) {
return pair.first;
}
};
std::list<T1> klist(in.size());
std::transform(in.begin(), in.end(), klist.begin(),
&take_first::op);
return klist;
}
HTH,
--
gpd