현재 효과적인 STL을 통해 작업 중입니다. 항목 5는 일반적으로 단일 요소 대응에 대해 범위 멤버 함수를 사용하는 것이 바람직하다는 것을 제안합니다. 현재 맵의 모든 값 (예 : 키가 필요하지 않음)을 벡터에 복사하고 싶습니다.
이를 수행하는 가장 깨끗한 방법은 무엇입니까?
현재 효과적인 STL을 통해 작업 중입니다. 항목 5는 일반적으로 단일 요소 대응에 대해 범위 멤버 함수를 사용하는 것이 바람직하다는 것을 제안합니다. 현재 맵의 모든 값 (예 : 키가 필요하지 않음)을 벡터에 복사하고 싶습니다.
이를 수행하는 가장 깨끗한 방법은 무엇입니까?
답변:
지도에서 얻은 반복자는 std :: pair를 참조하므로 여기서 범위를 쉽게 사용할 수 없습니다. 여기서 벡터에 삽입하는 데 사용하는 반복자는 벡터에 저장된 유형의 객체를 참조합니다. (키를 버리는 경우) 쌍이 아닙니다.
나는 그것이 명백한 것보다 훨씬 깨끗해지지 않는다고 생각합니다.
#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) );
}
매우 일반적이며 유용하다고 생각되면 그를 인정하는 것을 잊지 마십시오.
오래된 질문, 새로운 답변. C ++ 11에는 멋진 새로운 for 루프가 있습니다.
for (const auto &s : schemas)
names.push_back(s.first);
스키마는 std::map
이고 이름은 std::vector
.
이렇게하면 배열 (이름)이 맵 (스키마)의 키로 채워집니다. 변화 s.first
하는 s.second
값의 배열을 얻을.
const auto &s
reserve()
하면 또 다른 성능 향상을 얻을 수 있습니다. C ++ 11의 출현으로 이제 허용되는 솔루션이되어야합니다!
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) );
}
이 솔루션은 부스트 메일 링리스트 에있는 Michael Goldshteyn의 게시물을 기반으로 합니다 .
#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
모든 항목을 호출 합니다 . 작업 값은inputIterator
beginInputRange
endInputRange
outputIterator
.
전체 맵을 통해 작업하려면 map.begin () 및 map.end ()를 입력 범위로 사용합니다. 벡터에 맵 값을 저장하고 싶으므로 벡터에 back_inserter를 사용해야합니다 : back_inserter(your_values_vector)
. back_inserter는 주어진 (파레 미터로) 컬렉션의 끝에 새 요소를 푸시하는 특수 outputIterator입니다. 마지막 매개 변수는 unaryOperation이며 하나의 매개 변수 (inputIterator의 값) 만 사용합니다. 따라서 lambda :를 사용할 수 있습니다.
[](auto &kv) { [...] }
여기서 & kv는 맵 항목의 쌍에 대한 참조 일뿐입니다. 따라서 맵 항목의 값만 반환하려면 kv.second를 반환하면됩니다.
[](auto &kv) { return kv.second; }
나는 이것이 모든 의심을 설명한다고 생각합니다.
람다를 사용하면 다음을 수행 할 수 있습니다.
{
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); });
}
여기 내가 할 일이 있습니다.
또한 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)
);
}
한 가지 방법은 functor를 사용하는 것입니다.
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);
STL 알고리즘의 변형 함수를 사용해야합니다. 변형 함수의 마지막 매개 변수는 함수 객체, 함수 포인터 또는지도 항목을 벡터 항목으로 변환하는 람다 함수일 수 있습니다. 이 케이스 맵에는 벡터에 대해 int 유형이있는 항목으로 변환해야하는 유형 쌍이있는 항목이 있습니다. 다음은 람다 함수를 사용하는 솔루션입니다.
#include <algorithm> // for std::transform
#include <iterator> // for back_inserted
// Map of pair <int, string> need to convert to vector of string
std::map<int, std::string> mapExp = { {1, "first"}, {2, "second"}, {3, "third"}, {4,"fourth"} };
// vector of string to store the value type of map
std::vector<std::string> vValue;
// Convert function
std::transform(mapExp.begin(), mapExp.end(), std::back_inserter(vValue),
[](const std::pair<int, string> &mapItem)
{
return mapItem.second;
});
놀랍게도 아무도 가장 명백한 해결책을 언급하지 않았습니다 . 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());
}