代码之家  ›  专栏  ›  技术社区  ›  Amir Rachum

从映射中获取值列表

  •  12
  • Amir Rachum  · 技术社区  · 14 年前

    有没有一种STL方法可以从地图中获取值列表?

    我有:

    std::map<A,B> myMap;
    

    我想要一个只返回值列表的函数,即, std::list<B> (或为此事设定的)。 有内置的STL方法吗?

    6 回复  |  直到 7 年前
        1
  •  15
  •   Filip Sykala John Dibling    8 年前

    map 元素定义为 map::value_type 它的类型是 pair<A,B> . first 是钥匙和 second 是价值。你可以写一个 functor 提取 第二 从A 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;} );
    
        2
  •  2
  •   Johann Gerell    14 年前

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

    只是一个音符: std::list 很少是你真正想要使用的容器。当然,除非你真的 需要它的特定功能。

        3
  •  2
  •   Rob Kennedy    14 年前

    没有内置的东西,不。它足够简单,可以编写自己的函数:遍历映射。迭代器将为您提供 pair<A, B> . 添加每个 second 结果列表的值。

        4
  •  2
  •   aschepler    14 年前

    你不能仅仅“得到”这样一个列表,因为内脏中没有预先存在的列表,但是你可以建立一个:

    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());
    
        5
  •  1
  •   Puppy    14 年前

    当然。

    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编译器,首先你有我的同情心,第二,你需要为此建立一个快速的函数对象。

        6
  •  0
  •   Ben    7 年前

    你可以使用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;
    }