Скопировать карту значений вектора в STL


работая мой путь через эффективный STL на данный момент. Пункт 5 предполагает, что обычно предпочтительно использовать функции-члены диапазона для их одноэлементных аналогов. В настоящее время я хочу скопировать все значения на карте (т. е. - мне не нужны ключи) в вектор.

что самый чистый способ сделать это?

11 61

11 ответов:

вы не можете легко использовать диапазон здесь, потому что итератор, который вы получаете от карты, относится к паре std::, где итераторы, которые вы использовали бы для вставки в вектор, относятся к объекту типа, хранящегося в векторе, который (если вы отбрасываете ключ) не является парой.

Я действительно не думаю, что это становится намного чище, чем очевидно:

#include <map>
#include <vector>
#include <string>
using namespace std;

int main() {
    typedef map <string, int> MapType;
    MapType m;  
    vector <int> v;

    // populate map somehow

    for( MapType::iterator it = m.begin(); it != m.end(); ++it ) {
        v.push_back( it->second );
    }
}

который я, вероятно, переписал бы как функцию шаблона, если бы собирался использовать его более одного раза. Что-то например:

template <typename M, typename V> 
void MapToVec( const  M & m, V & v ) {
    for( typename M::const_iterator it = m.begin(); it != m.end(); ++it ) {
        v.push_back( it->second );
    }
}

вы могли бы использовать std::transform для этой цели. Я бы, возможно, предпочел версию Neils, хотя, в зависимости от того, что более читаемо.


пример xtofl (см. комментарии):

#include <map>
#include <vector>
#include <algorithm>
#include <iostream>

template< typename tPair >
struct second_t {
    typename tPair::second_type operator()( const tPair& p ) const { return     p.second; }
};

template< typename tMap > 
second_t< typename tMap::value_type > second( const tMap& m ) { return second_t<     typename tMap::value_type >(); }


int main() {
    std::map<int,bool> m;
    m[0]=true;
    m[1]=false;
    //...
    std::vector<bool> v;
    std::transform( m.begin(), m.end(), std::back_inserter( v ), second(m) );
    std::transform( m.begin(), m.end(), std::ostream_iterator<bool>( std::cout,     ";" ), second(m) );
}

очень общий, Не забудьте дать ему кредит, если вы найдете его полезным.

Если вы используете библиотеки Boost, вы можете использовать boost:: bind для доступа ко второму значению пары следующим образом:

#include <string>
#include <map>
#include <vector>
#include <algorithm>
#include <boost/bind.hpp>

int main()
{
   typedef std::map<std::string, int> MapT;
   typedef std::vector<int> VecT;
   MapT map;
   VecT vec;

   map["one"] = 1;
   map["two"] = 2;
   map["three"] = 3;
   map["four"] = 4;
   map["five"] = 5;

   std::transform( map.begin(), map.end(),
                   std::back_inserter(vec),
                   boost::bind(&MapT::value_type::second,_1) );
}

это решение основано на посте от Михаила Гольдштейна на увеличить список рассылки.

используя лямбды можно выполнить следующее:

{
   std::map<std::string,int> m;
   std::vector<int> v;
   v.reserve(m.size());
   std::for_each(m.begin(),m.end(),
                 [&v](const std::map<std::string,int>::value_type& p) 
                 { v.push_back(p.second); });
}

старый вопрос, новый ответ. С C++11 у нас есть причудливый новый цикл for:

for (const auto &s : schemas)
   names.push_back(s.first);

где схемы является std::map и имена std::vector.

это заполняет массив (имена) с ключами от карты (схемы); изменить s.first до s.second чтобы получить массив значений.

#include <algorithm> // std::transform
#include <iterator>  // std::back_inserter
std::transform( 
    your_map.begin(), 
    your_map.end(),
    std::back_inserter(your_values_vector),
    [](auto &kv){ return kv.second;} 
);

Извините, что я не добавил никаких объяснений - я думал, что код настолько прост, что не требует никаких объяснений. Итак:

transform( beginInputRange, endInputRange, outputIterator, unaryOperation)

эта функция называет unaryOperation на каждый товар от

вот что я бы сделал.
Также я бы использовал функцию шаблона, чтобы сделать конструкцию select2nd проще.

#include <map>
#include <vector>
#include <algorithm>
#include <memory>
#include <string>

/*
 * A class to extract the second part of a pair
 */   
template<typename T>
struct select2nd
{
    typename T::second_type operator()(T const& value) const
    {return value.second;}
};

/*
 * A utility template function to make the use of select2nd easy.
 * Pass a map and it automatically creates a select2nd that utilizes the
 * value type. This works nicely as the template functions can deduce the
 * template parameters based on the function parameters. 
 */
template<typename T>
select2nd<typename T::value_type> make_select2nd(T const& m)
{
    return select2nd<typename T::value_type>();
}

int main()
{
    std::map<int,std::string>   m;
    std::vector<std::string>    v;

    /*
     * Please note: You must use std::back_inserter()
     *              As transform assumes the second range is as large as the first.
     *              Alternatively you could pre-populate the vector.
     *
     * Use make_select2nd() to make the function look nice.
     * Alternatively you could use:
     *    select2nd<std::map<int,std::string>::value_type>()
     */   
    std::transform(m.begin(),m.end(),
                   std::back_inserter(v),
                   make_select2nd(m)
                  );
}

Я думал, что это должно быть

std:: transform( map.begin (), map.конец(), std:: back_inserter(vec), boost:: bind(&MapT:: value_type:: first, _1));

один из способов-использовать функтор:

 template <class T1, class T2>
    class CopyMapToVec
    {
    public: 
        CopyMapToVec(std::vector<T2>& aVec): mVec(aVec){}

        bool operator () (const std::pair<T1,T2>& mapVal) const
        {
            mVec.push_back(mapVal.second);
            return true;
        }
    private:
        std::vector<T2>& mVec;
    };


int main()
{
    std::map<std::string, int> myMap;
    myMap["test1"] = 1;
    myMap["test2"] = 2;

    std::vector<int>  myVector;

    //reserve the memory for vector
    myVector.reserve(myMap.size());
    //create the functor
    CopyMapToVec<std::string, int> aConverter(myVector);

    //call the functor
    std::for_each(myMap.begin(), myMap.end(), aConverter);
}

почему бы и нет:

template<typename K, typename V>
std::vector<V> MapValuesAsVector(const std::map<K, V>& map)
{
   std::vector<V> vec;
   vec.reserve(map.size());
   std::for_each(std::begin(map), std::end(map),
        [&vec] (const std::map<K, V>::value_type& entry) 
        {
            vec.push_back(entry.second);
        });
    return vec;
}

использование:

auto vec = MapValuesAsVector (anymap);

удивлена, что никто не упомянул самое очевидное решение, используйте конструктор std::vector.

template<typename K, typename V>
std::vector<std::pair<K,V>> mapToVector(const std::unordered_map<K,V> &map)
{
    return std::vector<std::pair<K,V>>(map.begin(), map.end());
}