Есть ли способ stl получить список значений из карты?
i.e, я:
std::map<A,B> myMap;
и мне нужна функция, которая вернет только список значений, т.е. std::list<B>
(или, если это необходимо).
Есть ли встроенный способ stl для этого?
Есть ли способ stl получить список значений из карты?
i.e, я:
std::map<A,B> myMap;
и мне нужна функция, которая вернет только список значений, т.е. std::list<B>
(или, если это необходимо).
Есть ли встроенный способ stl для этого?
A map
определяется как map::value_type
, а его тип - pair<A,B>
. first
- это ключ, а second
- значение. Вы можете написать functor, чтобы извлечь second
из value_type
и скопировать его в vector
(или a list
или что бы вы ни хотели.) Лучший способ сделать копирование - использовать transform
, который делает то, что подразумевает его название: оно принимает значение одного типа и преобразует его в другой тип значения.
Вот полный рабочий пример:
#include <cstdlib>
#include <map>
#include <string>
#include <algorithm>
#include <iterator>
#include <vector>
#include <iostream>
using namespace std;
typedef map<unsigned, string> MyMap;
MyMap my_map;
struct get_second : public std::unary_function<MyMap::value_type, string>
{
string operator()(const MyMap::value_type& value) const
{
return value.second;
}
};
int main()
{
my_map[1] = "one";
my_map[2] = "two";
my_map[3] = "three";
my_map[4] = "four";
my_map[5] = "five";
// get a vector of values
vector<string> my_vals;
transform(my_map.begin(), my_map.end(), back_inserter(my_vals), get_second() );
// dump the list
copy( my_vals.begin(), my_vals.end(), ostream_iterator<string>(cout, "\n"));
}
Если у вас есть компилятор, который поддерживает С++ 0x lambdas, вы можете полностью исключить функтор. Это очень полезно для того, чтобы сделать код более читаемым и, возможно, более простым в обслуживании, поскольку вы не получаете десятки маленьких одноразовых функторов, плавающих в вашей кодовой базе. Здесь, как вы изменили бы код выше, чтобы использовать лямбда:
transform(my_map.begin(), my_map.end(), back_inserter(my_vals), [](const MyMap::value_type& val){return val.second;} );
Там ничего не построено, нет. Это достаточно просто, чтобы написать свою собственную функцию: Итерации по карте. Итератор даст вам pair<A, B>
. Добавьте каждое значение second
в список результатов.
Один из многих "встроенных" способов, конечно, самый очевидный. Просто перебирайте все элементы пары, которые упорядочены по ключу (pair::first
), и добавьте значение (pair::second
) в новый контейнер, который вы можете построить с правильной способностью избавиться от избыточных распределений во время итерации и добавления.
Просто примечание: std::list
редко является контейнером, который вы действительно хотите использовать. Если, конечно, вы действительно, действительно do нуждаются в его специфических особенностях.
Вы не можете просто "получить" такой список, потому что нет существующего списка, хранящегося где-либо в кишках, но вы можете его создать:
typedef std::map<A,B> myMapType;
myMapType myMap;
std::list<B> valueList;
for (myMapType::const_iterator it=myMap.begin(); it!=myMap.end(); ++it) {
valueList.push_back( it->second );
}
Или, если вам действительно нравится путь STL:
class GetSecond {
template<typename T1, typename T2>
const T2& operator()( const std::pair<T1,T2>& key_val ) const
{ return key_val.second; }
};
typedef std::map<A,B> myMapType;
myMapType myMap;
std::list<B> valueList;
std::transform(myMap.begin(), myMap.end(), std::back_inserter(valueList),
GetSecond());
Конечно.
std::list<B> list;
std::for_each(myMap.begin(), myMap.end(), [&](const std::pair<const A, B>& ref) {
list.push_back(ref.second);
});
Если у вас нет компилятора С++ 0x, сначала у вас есть мои симпатии, и, во-вторых, вам нужно будет создать быстрый объект функции для этой цели.
Вы можете использовать boost transform_iterator
: http://www.boost.org/doc/libs/1_64_0/libs/iterator/doc/transform_iterator.html
struct GetSecond {
template <typename K, typename T>
const T& operator()(const std::pair<K, T> & p) const { return p.second; }
template <typename K, typename T>
T& operator()(std::pair<K, T> & p) const { return p.second; }
};
template <typename MapType>
auto begin_values(MapType& m) -> decltype(boost::make_transform_iterator(m.begin(), GetSecond())) {
return boost::make_transform_iterator(m.begin(), GetSecond());
}
template <typename MapType>
auto end_values(MapType& m) -> decltype(boost::make_transform_iterator(m.end(), GetSecond())) {
return boost::make_transform_iterator(m.end(), GetSecond());
}
template <typename MapType>
struct MapValues {
MapType & m;
MapValues(MapType & m) : m(m) {}
typedef decltype(begin_values(m)) iterator;
iterator begin() { return begin_values(m); }
iterator end() { return end_values(m); }
};
template <typename MapType>
MapValues<MapType> get_values(MapType & m) {
return MapValues<MapType>(m);
}
int main() {
std::map<int, double> m;
m[0] = 1.0;
m[10] = 2.0;
for (auto& x : get_values(m)) {
std::cout << x << ',';
x += 1;
}
std::cout << std::endl;
const std::map<int, double> mm = m;
for (auto& x : get_values(mm)) {
std::cout << x << ',';
}
std::cout << std::endl;
}