是否存在C++的std::map
等效于Java Map的keySet()
方法?
Java的keySet()
方法返回"此映射中包含的键的集合视图"
std::set
,这可能并不理想:如果您只想遍历键,您不希望有创建整个新容器的开销。std::map
迭代器转换为某种类型的迭代器,当解除引用时仅产生键。使用Boost Transform Iterator可以非常简单地实现这一点。#include <functional>
#include <boost/iterator/transform_iterator.hpp>
// You may already have a select1st implementation; if not, you should :-)
template <typename Pair>
struct select1st
: std::unary_function<const Pair&, const typename Pair::first_type&>
{
const typename Pair::first_type& operator()(const Pair& p) const
{
return p.first;
}
};
template <typename C>
boost::transform_iterator<
select1st<typename C::value_type>, typename C::const_iterator
> begin_keys(const C& c)
{
return boost::make_transform_iterator(
c.begin(), select1st<typename C::value_type>()
);
}
template <typename C>
boost::transform_iterator<
select1st<typename C::value_type>, typename C::const_iterator
> end_keys(const C& c)
{
return boost::make_transform_iterator(
c.end(), select1st<typename C::value_type>()
);
}
有了这些实用函数,您可以将任何一组std::map
迭代器(或其他任何成对关联容器的迭代器)转换为仅包含键的范围。例如:
#include <iostream>
#include <iterator>
#include <map>
int main()
{
std::map<int, int> m;
m.insert(std::make_pair(1, 2));
m.insert(std::make_pair(2, 4));
m.insert(std::make_pair(3, 6));
std::copy(
begin_keys(m), end_keys(m),
std::ostream_iterator<int>(std::cout, ","));
}
1,2,3,
如果您确实想要一个包含键的 std::set
,您可以使用这些迭代器轻松创建一个:
std::set<int> s(begin_keys(m), end_keys(m));
总体而言,这是一个更加灵活的解决方案。
如果您没有Boost,或者不想使用Boost,或者无法使用Boost,那么可以很容易地实现这个特定的变换迭代器:
#include <iterator>
template <typename C>
class key_iterator
: public std::iterator<
std::bidirectional_iterator_tag,
typename C::key_type,
typename C::difference_type,
typename C::pointer,
typename C::reference
>
{
public:
key_iterator() { }
explicit key_iterator(typename C::const_iterator it) : it_(it) { }
typename const C::key_type& operator*() const { return it_->first; }
typename const C::key_type* operator->() const { return &it_->first; }
key_iterator& operator++() { ++it_; return *this; }
key_iterator operator++(int) { key_iterator it(*this); ++*this; return it; }
key_iterator& operator--() { --it_; return *this; }
key_iterator operator--(int) { key_iterator it(*this); --*this; return it; }
friend bool operator==(const key_iterator& lhs, const key_iterator& rhs)
{
return lhs.it_ == rhs.it_;
}
friend bool operator!=(const key_iterator& lhs, const key_iterator& rhs)
{
return !(lhs == rhs);
}
private:
typename C::const_iterator it_;
};
template <typename C>
key_iterator<C> begin_keys(const C& c) { return key_iterator<C>(c.begin()); }
template <typename C>
key_iterator<C> end_keys(const C& c) { return key_iterator<C>(c.end()); }
或许以下内容会有用:
#include <iostream>
#include <iterator>
#include <algorithm>
#include <map>
#include <set>
#include <string>
template< class Key,
class T,
class Comparator,
class MapAllocator,
class SetAllocator>
void make_key_set(const std::map<Key,T,Comparator,MapAllocator>& map,
std::set<Key,Comparator,SetAllocator>& set)
{
set.clear();
typedef typename std::map<Key,T,Comparator,MapAllocator> map_type;
typename map_type::const_iterator itr = map.begin();
while (map.end() != itr)
{
set.insert((itr++)->first);
}
}
int main()
{
std::map<std::string, double> m;
m["one"] = 1.1;
m["two"] = 2.2;
m["three"] = 3.3;
std::set<std::string> key_set;
make_key_set(m,key_set);
std::copy(key_set.begin(), key_set.end(),
std::ostream_iterator<std::string>(std::cout, "\n"));
return 0;
}
对于 make_key_set 函数的重载,可以接受 STL 兼容的序列,如 std::vector、std::deque 或 std::list,示例如下:
template< class Key,
class T,
class Comparator,
class MapAllocator,
class SeqAllocator,
template<class,class> class Sequence>
void make_key_set(const std::map<Key,T,Comparator,MapAllocator>& map,
Sequence<Key,SeqAllocator>& sequence)
{
sequence.clear();
typedef typename std::map<Key,T,Comparator,MapAllocator> map_type;
typename map_type::const_iterator itr = map.begin();
while (map.end() != itr)
{
sequence.push_back((itr++)->first);
}
}
set.insert((itr++)->first);
替换为set.insert(set.end(),(itr++)->first);
来使其变为O(n)。 - Notinlist这里是一行加上一点的代码:
map<K,V> m;
...
// Useful stuff goes here
...
set<K> s;
transform(m.begin(), m.end(), inserter(s, s.begin()), select1st<pair<K,V> >());
如果您没有 select1st
:
template <class P>
struct select1st : public std::unary_function<P, typename P::first_type>
{
const typename P::first_type& operator()(const P &arg) const { return arg.first; }
};
你可以自己实现它:
vector<T> keys;
for (map<T,S>::iterator it=m.begin(); it!=m.end; it++)
keys.push_back(it->first)
std::set<T> keys
真正匹配功能呢? - R Samuel KlatchkoBoost.Range 提供了 boost::adaptors::map_values:
std::map my_map;
for (auto &value : my_map | boost::adaptors::map_values) {
//...
}
std::map
中没有成员函数来实现这个功能。我知道自己实现很简单,但是很多东西都已经被包含在STL中了。如果有人知道为什么不包含它的理由,我会很感兴趣听听。 - Tyler McHenrystd::string
。 - Tyler McHenry