Есть ли в Java Map keySet () эквивалентный для C ++ std :: map? - PullRequest
10 голосов
/ 18 марта 2010

Есть ли эквивалент JavaS keySet () для C ++ std::map?

Метод Java keySet() возвращает "набор ключей, содержащихся в этой карте."

Ответы [ 5 ]

8 голосов
/ 24 февраля 2011

Все ответы, представленные до настоящего времени, в конечном итоге создают 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());   }

Использование для этого такое же, как и для версии Boost.

1 голос
/ 18 марта 2010

Возможно, может быть полезно следующее:

#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);
   }
}
1 голос
/ 18 марта 2010

Вот один-единственный бит:

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; }
};
0 голосов
/ 09 июня 2014

Boost.Range обеспечивает это как boost :: adapters :: map_values ​​:

std::map my_map;
for (auto &value : my_map | boost::adaptors::map_values) {
    //...
}
0 голосов
/ 18 марта 2010

Вы можете реализовать это самостоятельно:

vector<T> keys;
for (map<T,S>::iterator it=m.begin(); it!=m.end; it++)
  keys.push_back(it->first)
...