从地图中获取值列表

时间:2010-11-16 15:14:48

标签: c++ list stl map

是否有一种从地图中获取值列表的方法?

即,我有:

std::map<A,B> myMap;

我想要一个只返回值列表的函数,即std::list<B>(或为此设置。 有没有内置的方法来做到这一点?

6 个答案:

答案 0 :(得分:15)

map元素定义为map::value_type,其类型为pair<A,B>first是关键,second是值。您可以撰写functorsecond中提取value_type,然后将其复制到vector(或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"));
}

编辑:

如果您的编译器支持C ++ 0x lambdas,则可以完全取消仿函数。这对于使代码更具可读性和可论证性更易于维护非常有用,因为您最终不会在代码库中出现数十个小的一次性仿函数。以下是如何更改上面的代码以使用lambda:

transform(my_map.begin(), my_map.end(), back_inserter(my_vals), [](const MyMap::value_type& val){return val.second;} );

答案 1 :(得分:2)

许多“内置”方式中的一种当然是最明显的方式。只需迭代按键(pair::first)排序的所有对元素,并将值(pair::second)添加到新容器中,您可以使用正确的容量构建该容器以消除多余的分配在迭代和添加过程中。

只需注意:std::list很少是您实际想要使用的容器。当然,除非你真的需要它的特定功能。

答案 2 :(得分:2)

没有内置任何东西,没有。但是编写自己的函数很简单:迭代地图。迭代器会给你一个pair<A, B>。将每个second值添加到结果列表中。

答案 3 :(得分:2)

你不能只是“得到”这样一个列表,因为没有预先存在的列表存储在内容的任何地方,但你可以构建一个:

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());

答案 4 :(得分:1)

不确定

std::list<B> list;
std::for_each(myMap.begin(), myMap.end(), [&](const std::pair<const A, B>& ref) {
    list.push_back(ref.second);
});

如果你没有C ++ 0x编译器,首先你有我的同情心,其次,你需要为此目的构建一个快速的函数对象。

答案 5 :(得分:0)

您可以使用提升transform_iteratorpython: how to have a property and with a setter function that detects all changes that happen to the value

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