Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

To retrieve Keys or values of a Map

0 views
Skip to first unread message

Saeed Amrollahi

unread,
Nov 4, 2009, 4:44:54 AM11/4/09
to
Dear all

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.

Alan Woodland

unread,
Nov 4, 2009, 7:05:38 AM11/4/09
to

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

Saeed Amrollahi

unread,
Nov 5, 2009, 8:12:32 AM11/5/09
to

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

mzdude

unread,
Nov 5, 2009, 9:30:33 AM11/5/09
to

#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;
}

Saeed Amrollahi

unread,
Nov 6, 2009, 11:23:06 AM11/6/09
to
> }- Hide quoted text -
>
> - Show quoted text -

Thank you.

Joshua Maurice

unread,
Nov 6, 2009, 4:41:31 PM11/6/09
to

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.

gpderetta

unread,
Nov 12, 2009, 12:03:43 PM11/12/09
to
On Nov 4, 1:05 pm, Alan Woodland <a...@aberystwyth.ac.uk> wrote:
>
> 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;
>
> }
>

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

0 new messages