unique_copy elements value from map to vector - c++

I have a map<K, V> and I want to use unique_copy to put the values into a vector<V>.
I tried this but it doesn't work:
#include <iostream>
#include <map>
#include <algorithm>
#include <vector>
#include <functional>
using namespace std;
using namespace placeholders;
int main() {
map<std::string, int> mp;
mp["1"] = 1;
mp["2"] = 2;
mp["3"] = 3;
mp["4"] = 3;
mp["5"] = 3;
mp["6"] = 4;
mp["7"] = 2;
vector<int> vec;
unique_copy( mp.begin(), mp.end(),
back_inserter(vec),
bind(&map<std::string, int>::value_type::second, _1) );
for( auto& i : vec )
cout<< i <<" ";
}
Expected output:
1 2 3 4 2
All google searches return ways to use transform but I need unique_copy. Is there any way to make this work?

There's no way to do this directly, because the value type of the map iterator and the vector iterator are not compatible. You really need a transform of some sort, or an iterator adaptor.
You could use boost::transform_iterator for this:
auto getValue = [](const std::map<std::string, int>::value_type &pair) { return pair.second; };
unique_copy(
boost::make_transform_iterator(mp.begin(), getValue),
boost::make_transform_iterator(mp.end(), getValue),
back_inserter(vec)
);
If you cannot use Boost, you'll have to write such an iterator adaptor yourself:
template <class T_PairIterator>
struct SecondIterator
{
typedef T_PairIterator PairIterator;
typedef typename std::iterator_traits<PairIterator>::iterator_category iterator_category;
typedef typename std::iterator_traits<PairIterator>::value_type::second_type value_type;
typedef typename std::iterator_traits<PairIterator>::difference_type difference_type;
typedef value_type *pointer;
typedef value_type &reference;
PairIterator it;
SecondIterator() {}
explicit SecondIterator(PairIterator it) : it(it) {}
pointer operator-> () const { return &it->second; }
reference operator* () const { return it->second; }
SecondIterator& operator++ () { ++it; return *this; }
SecondIterator operator++ (int) { SecondIterator ret(*this); ++it; return ret; }
};
template <class T>
bool operator== (const SecondIterator<T> &lhs, const SecondIterator<T> &rhs)
{ return lhs.it == rhs.it; }
template <class T>
bool operator!= (const SecondIterator<T> &lhs, const SecondIterator<T> &rhs)
{ return !(lhs == rhs); }
template <class T>
SecondIterator<T> makeSecondIterator(const T &it)
{ return SecondIterator<T>(it); }
You could then use it like this:
unique_copy(
makeSecondIterator(mp.begin()),
makeSecondIterator(mp.end()),
back_inserter(vec)
);
Of course, the adaptor could be made a bit more generic (perhaps usable for first as well), and/or more encapsulated (it needn't be public); it would also need proper handling for const-iterators. But the above should be enough to give you the idea.

std::copy followed by vec.erase( std::unique( vec.begin(), vec.end() ), vec.end() ); will end up in the same place as unique_copy with a transform would. It may use extra memory in the middle (before removing redundant entries) but is pretty clean.
A manual copy is another option:
if(!src.empty()){
auto* prev = &src.begin()->second;
dest.push_back(*prev);
for(auto it = std::next(src.begin()); it != sec.end(); ++it){
if (it->second == *prev) continue;
prev=&it->second;
dest.push_back(*prev);
}
}
with the note thay prev is technically redundant (use dest.back() instead of *prev except when push_backing -- there use ->second).

As Vijay says in his comment, you could use a std::set instead of a vector (if you don't need the individual features of a vector, of course, like contiguous storage, custom ordering or random access). In this case the std::set::insert will already take care of removing duplicates and you can use std::transform in the way you tried:
std::set<int> set;
std::transform( mp.begin(), mp.end(), std::inserter(set),
bind(&std::map<std::string, int>::value_type::second, _1) );
As to your modified question
std::set won't insert the value if it is already in the set but I
don't want consecutive duplicates.
Well, in this case just do a normal copy (i.e. std::transform) into the vector and do a std::unique afterwards, which will just remove all consecutive duplicates:
std::transform( mp.begin(), mp.end(), std::inserter(vec),
bind(&std::map<std::string, int>::value_type::second, _1) );
vec.erase( std::unique(vec.begin(), vec.end()), vec.end() );

Related

can one use templated begin/end methods in range based for loops

I deal with a class that is meant to be iterable in range based for loops, so it defines an iterator class, begin- and end-method. Now in the example I'm working on, these three are templated (I have this minimal example, where the template parameter isn't really meaningful but just has templated begin and end):
#include <cstddef>
#include <tuple>
#include <vector>
struct Iterable {
using Widget = std::tuple<int, float>;
template <typename access_type>
struct Iterator {
Iterable* m_iterable;
std::size_t m_pos;
bool operator==( const Iterator& other ) { return m_iterable == other.m_iterable && m_pos == other.m_pos; }
bool operator!=( const Iterator& other ) { return !( this->operator==( other ) ); }
access_type operator*() {
Widget tmp = m_iterable->m_storage[m_pos];
return std::get<access_type>( tmp );
}
Iterator operator++() {
m_pos++;
return *this;
}
};
template <typename access_type = int>
Iterator<access_type> begin() {
return {this, 0};
}
template <typename access_type = int>
Iterator<access_type> end() {
return {this, m_storage.size()};
}
std::vector<Widget> m_storage;
};
Now this iterable works in a range based for loop
Iterable container;
for (auto element: container) { … }
This uses begin<int> and end<int> as is somewhat visible from cppinsights (note the type of the iterator in the range based version of the loop).
What is not clear to me is, is there a way to specify the template parameters for the for loop other than retreating to a pre-c++11 loop?
for (auto iter = container.begin<float>(); iter != container.end<float>(); ++iter) { … }
EDIT to clarify the scope of the discussion. The iterable class is considered to be preexisting in upstream code, I don't want to discuss the reasons for putting it into the world. Someone else's code just exist and I have to deal with it.
see also compiler-explorer
What you would need is an adapter that wraps the container and provides the iterators that you want it to have. That would give you a class like
template<typename T>
struct Adapter
{
Iterable & it;
Adapter(Iterable& it) : it(it) {}
auto begin()
{
return it.begin<T>();
}
auto end()
{
return it.end<T>();
}
};
and you would use it like
int main()
{
Iterable container;
for ( auto element : Adapter<float>{container} )
{
static_assert( std::is_same_v<decltype( element ), float> );
}
}

How to implement end sentinel for back_insert_iterator?

I want to fill a container by consequtive values of iterators to elements of another container (often occured real life problem), say:
std::container1< T > c1{/* initialized */};
assert(!c1.empty());
std::continer2< typename std::container1< T >::iterator > c2;
auto it = std::begin(c1), const end = std::end(c1);
do { c2.push_back(it); } while (++it != end);
There is attractive std::iota algorithm in STL, but it is range-based and for std::back_inserter(c2) there is no way to achieve desired currently. However in the next versions of STL I can expect the iota algorithm of the form:
template< typename ForwardIterator, typename EndSentinel, typename T >
void
iota(ForwardIterator first, EndSentinel last, T value)
{
for (; first != last; ++first) {
*first = value;
++value;
}
}
How to implement EndSentinel and operator != (ForwardIterator, EndSentinel) to make above iota stop after exactly c1.size() step of the for loop in iota(std::back_inserter(c1), something(c1, c1.size()), std::begin(c1))?
There is no sentinel for std::back_insert_iterator (or any OutputIterator) and also no equality operator, because an output iterator is an "unlimited sequence": You can append elements to the end of a container or write to a file until you run out of memory or disk space.
However, it makes sense to have an output iterator with a sentinel if you need to call an algorithm which expects an "output sentinel" (because not expecting one may be unsafe if the output is a "limited sequence", such as a pre-allocated std::vector). Such an algorithm could look like:
template<typename InIter, typename InSentinel, typename OutIter, typename OutSentinel>
OutIter modernAlgorithm(InIter first, InSentinel last, OutIter outFirst, OutSentinel outLast);
In this case, all you need is a trivial sentinel, which compares unequal to everything. See also this answer.
template<typename T>
struct TrivialSentinel
{
bool operator==(const T&) { return false; }
bool operator!=(const T&) { return true; }
friend bool operator==(const T&, TrivialSentinel&) { return false; }
friend bool operator!=(const T&, TrivialSentinel&) { return true; }
};
modernAlgorithm(v.begin(), v.end(), std::back_inserter(r), TrivialSentinel<decltype(std::back_inserter(r))>());
(This may seem odd, but it does make sense if you consider that even if you repeat the same operation *out = expr on the same value of out, the output will be in a different state each time, so in a certain sense, no two output iterators are ever necessarily equivalent...)
However, older algorithms often don't allow the iterator and sentinel to have different types:
template<typename InIter, typename OutIter>
OutIter olderAlgorithm(InIter first, InIter last, OutIter outFirst, OutIter outLast);
In this case, you can write a sub class or wrapper of std::back_insert_iterator, which has a default constructor and always compares unequal to itself.
This is easy in C++20, where std::back_insert_iterator has a default constructor:
// C++20
template<typename C>
struct BackInsertIteratorWithSentinel : public std::back_insert_iterator<C>
{
BackInsertIteratorWithSentinel() {} // C++20 only
BackInsertIteratorWithSentinel(C& c) : std::back_insert_iterator<C>(c) {}
bool operator==(const BackInsertIteratorWithSentinel&) { return false; }
bool operator!=(const BackInsertIteratorWithSentinel&) { return true; }
};
template<typename C>
BackInsertIteratorWithSentinel<C> BackInserterWithSentinel(C& c)
{
return BackInsertIteratorWithSentinel<C>(c);
}
template<typename C>
BackInsertIteratorWithSentinel<C> BackInserterWithSentinel()
{
return BackInsertIteratorWithSentinel<C>();
}
olderAlgorithm(v.begin(), v.end(), BackInserterWithSentinel(r), BackInserterWithSentinel<std::vector<int> >());
Note that even in C++20, std::back_insert_iterator does not have an equality operator.
If you have to support older versions of C++, then you may have to implement your own std::back_insert_iterator from scratch, or use boost::optional or in-place construction to work around the lack of a default constructor.
Full test program for C++20
I dont think you can do it - or maybe I dont understand your question, but..
according to http://en.cppreference.com/w/cpp/algorithm/iota, this algorithm works on existing range of elements - so it does not make sense to use it with: std::back_inserter as first iterator which basicly is used to insert elements.
I want to fill a container by consequtive values of iterators to elements of another container
a different solution which uses generate_n:
live
std::vector<int> src = {0,1,2,3};
std::vector<std::vector<int>::iterator> dst;
std::generate_n(std::back_inserter(dst), src.size(), [it=src.begin()]() mutable {return it++;});
Your question includes an iota implementation which is different than the one in the standard I believe. Here is the standard version I know http://en.cppreference.com/w/cpp/algorithm/iota.
Your iota (which I will rename it as miota in my code) allows different type of iterators for begin and end.
What you want in the algorithm is; end sentinel needs to be different from begin (the inserter) until all values are processed. For processing values you only take one object and you use increment and copy-construction on that object.
Therefore, your end sentinel should know about the value processing and when finished the end sentinel should become equal to the inserter somehow.
I did it via holding begin/end iterators of the original container in a class called IotaHelper. This uses shared_ptr for sharing state with the sentinel class which is called IotaEndSentinel.
When you increment the value inside miota, it actually increments the begin iterator of the IotaHelper. When you check equality with the inserter and the sentinel it actually checks the iterator equality inside the IotaHelper.
All code with a basic example is here:
#include <iterator>
#include <numeric>
#include <vector>
#include <iostream>
#include <utility>
#include <memory>
template< typename ForwardIterator, typename EndSentinel, typename T >
void miota(ForwardIterator first, EndSentinel last, T value)
{
for (; first != last; ++first) {
*first = value;
++value;
}
}
template<typename Container>
struct IotaHelper
{
using Iterator = typename Container::iterator;
using IteratorPair = std::pair<Iterator, Iterator>;
IotaHelper(Iterator begin, Iterator end)
:
pair(std::make_shared<IteratorPair>(begin, end))
{ }
operator Iterator()
{
return pair->first;
}
IotaHelper& operator++()
{
++pair->first;
return *this;
}
std::shared_ptr<IteratorPair> pair;
};
template<typename Container>
struct IotaEndSentinel
{
using Helper = IotaHelper<Container>;
using Iterator = typename Helper::Iterator;
IotaEndSentinel(const Helper& helper)
:
helper(helper)
{}
template<typename C>
friend bool operator!=(const std::back_insert_iterator<C>& bii,
const IotaEndSentinel& sentinel)
{
return sentinel.helper.pair->first != sentinel.helper.pair->second;
}
Helper helper;
};
int main()
{
using Container0 = std::vector<int>;
using Container1 = std::vector<Container0::iterator>;
Container0 c0 = {1, 2, 3, 4, 5};
Container1 c1;
IotaHelper<Container0> iotaHelper(c0.begin(), c0.end());
miota(std::back_inserter(c1),
IotaEndSentinel<Container0>(iotaHelper),
iotaHelper);
std::cout << "Result: ";
for (auto iter : c1)
{
std::cout << *iter << ", ";
}
std::cout << std::endl;
}
I have tried to do this because it was fun. But please don't use this method for hacking output iterators like back_insert_iterator and make a generic method for yourself for different containers.
template<typename SourceContainer, typename IteratorContainer>
void FillIterators(SourceContainer& sc, IteratorContainer& ic)
{
for (auto iter = sc.begin(); iter != sc.end(); ++iter)
{
ic.insert(ic.end(), iter);
}
}
EDIT:
After using heap-allocation that code was smelling to me. Instead of trying to reason about the "value and the process" we can reason about the "iterators and the process".
We can build an iterator-wrapper which contains the process iterator and the insert iterator together.
When the algorithm needs to dereference the wrapper, it will return the insert iterator.
When the algorithm needs to compare to other "wrapper or sentinel", wrapper will compare the process iterator.
In the end we can use such iterator for both std::iota and your miota.
Complete example is here:
#include <iterator>
#include <numeric>
#include <vector>
#include <iostream>
#include <utility>
#include <memory>
template< typename ForwardIterator, typename EndSentinel, typename T >
void miota(ForwardIterator first, EndSentinel last, T value)
{
for (; first != last; ++first) {
*first = value;
++value;
}
}
template<typename InsertIterator, typename Iterator>
struct InsertWrapper
{
InsertWrapper(const InsertIterator& inserter, const Iterator& iter)
:
inserter(inserter),
iter(iter)
{ }
bool operator!=(const InsertWrapper& other) const
{
//only compare process iterators
return iter != other.iter;
}
bool operator!=(const Iterator& sentinel) const
{
//compare process iterator against the sentinel
return iter != sentinel;
}
InsertIterator& operator*()
{
//return inserter for dereference
return inserter;
}
InsertWrapper& operator++()
{
//iterate inserter as the process progresses
++inserter;
++iter;
return *this;
}
InsertIterator inserter;
Iterator iter;
};
template<typename InsertIterator, typename Iterator>
InsertWrapper<InsertIterator, Iterator> WrapInserter(const InsertIterator& inserter,
const Iterator& iter)
{
return InsertWrapper<InsertIterator, Iterator>(inserter, iter);
}
int main()
{
using Container0 = std::vector<int>;
using Container1 = std::vector<Container0::iterator>;
Container0 c0 = {1, 2, 3, 4, 5};
Container1 c1;
//use wrapper as usual iterator begin/end
std::iota(WrapInserter(std::back_inserter(c1), c0.begin()),
WrapInserter(std::back_inserter(c1), c0.end()),
c0.begin());
std::cout << "std::iota result: ";
for (auto iter : c1)
{
std::cout << *iter << ", ";
}
std::cout << std::endl;
c1.clear();
miota(WrapInserter(std::back_inserter(c1), c0.begin()),
c0.end(), //end iterator as sentinel
c0.begin());
std::cout << "miota result: ";
for (auto iter : c1)
{
std::cout << *iter << ", ";
}
std::cout << std::endl;
}

Confusion regarding std::transform - converting std::map's value_type::second to a std::vector

Hi can anyone tell me why VS2010 gives me an error with this code, I can't see what's the problem with it?
Error code : error C2679: binary '=' : no operator found which takes a right-hand operand of type 'std::vector<_Ty>' (or there is no acceptable conversion)
// Elements container
typedef std::vector<CFVFElementPtr> ElementArray;
typedef std::map<CVertexSemantic::Type, ElementArray> ElementsMap;
// Create an empty array of elements
ElementsMap::value_type::second_type allElements;
// Concatinate each std::vector found within the map
std::transform(m_elementsMap.begin(), m_elementsMap.end(),
std::insert_iterator<ElementArray>(allElements, allElements.end()),
select2nd<ElementsMap::value_type>() );
All I am trying to do is this
for (auto i = m_elementsMap.begin(); i != m_elementsMap.end(); ++i)
{
const ElementArray& elements = (*i).second;
allElements.insert(allElements.end(), elements.begin(), elements.end());
}
As a response to Pablo, I tried creating a custom iterator that accepts an array of ElementArray, but I'm now getting a bucket load of errors.
template < class Container >
class container_insert_interator
{
public:
typedef container_insert_interator<Container> this_type;
typedef Container container_type;
typedef typename Container::const_reference const_reference;
typedef typename Container::value_type valty;
explicit container_insert_interator (Container& cont, typename Container::iterator iter)
: container(&cont), iter(iter)
{ }
this_type& operator = (typename const_reference value)
{
iter = container->insert( iter, std::begin(value), std::end(value) );
++iter;
return *this;
}
this_type& operator* ()
{
return *this;
}
this_type& operator++ ()
{
return *this;
}
this_type operator++ (int)
{
return *this;
}
protected:
Container* container; // pointer to container
typename Container::iterator iter ; // iterator into container
};
The problem is ElementsMap::value_type::second_type is ElementArray. That is, you're trying to insert instances of ElementArray into an ElementArray, which really holds instances of CFVFElementPtr.
Update: Changing your declaration of operator= from
this_type& operator = (typename const_reference value)
to
template<typename OtherContainer>
this_type& operator = ( OtherContainer const& value)
almost works. Except that neither VS 2010 or GCC 4.6.1 provide the vector::insert overload that returns an iterator. You'll probably need a newer compiler if you want your ranged insert to return an iterator to replace iter.
Changing the implementation to always insert at the end, namely
container->insert( container->end(), std::begin(value), std::end(value) );
in operator= compiles fine with GCC 4.6.1 (and, of course, you can remove all references to iter in your iterator class).
You might consider using a functor that can append elements to your target array along with std::for_each to walk the map:
struct ElementArray_appender
{
ElementArray_appender( ElementArray& dest_) : dest(dest_) {
};
void operator()( ElementsMap::value_type const& map_item) {
ElementArray const& vec( map_item.second);
dest.insert( dest.end(), vec.begin(), vec.end());
};
private:
ElementArray& dest;
};
// in whatever function:
std::for_each( m_elementsMap.begin(), m_elementsMap.end(), ElementArray_appender(allElements));
I found the answer, the poblem was with my custom iterator. The correct one that works is
template < class Container >
class container_back_insert_interator
{
public:
typedef container_back_insert_interator<Container> this_type;
typedef Container container_type;
typedef typename container_type::const_reference const_reference;
typedef typename container_type::value_type valty;
explicit container_back_insert_interator (container_type& cont)
: container(&cont)
{ }
this_type& operator = (const_reference value)
{
container->insert( container->end(), std::begin(value), std::end(value) );
return *this;
}
this_type& operator* ()
{
return *this;
}
this_type& operator++ ()
{
return *this;
}
this_type operator++ (int)
{
return *this;
}
protected:
container_type* container; // pointer to container
};
template < class Container >
inline container_back_insert_interator<Container> container_back_inserter(Container& cont)
{
return container_back_insert_interator<Container>(cont);
}
However, I must warn that if you do use this in Visual Studio 2010 you will have to implement an SGI form of std::transform. The version that ships with VS2010 for some reason throws numerous errors, all of which lie within the <xutility> header.
This std::transform works just fine.

Getting a list of values from a map

Is there an stl way to get a list of values from a map?
i.e, I have:
std::map<A,B> myMap;
and I would like a function that will return just the list of values, i.e, std::list<B> (or set for that matter.
Is there a built-in stl way to do this?
A map element is defined as a map::value_type, and the type of it is a pair<A,B>. first is the key and second is the value. You can write a functor to extract second from a value_type, and copy that in to a vector (or a list, or whatever you want.) The best way to do the copying is to use transform, which does just what its name implies: it takes a value of one type and transforms it to a different type of value.
Here's a complete working example:
#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"));
}
EDIT:
If you have a compiler that supports C++0x lambdas, you can eliminate the functor entirely. This is very useful for making code more readable and, arguable, easier to maintain since you don't end up with dozens of little one-off functors floating around in your codebase. Here's how you would change the code above to use a lambda:
transform(my_map.begin(), my_map.end(), back_inserter(my_vals), [](const MyMap::value_type& val){return val.second;} );
There's nothing built in, no. It's simple enough to write your own function, though: Iterate over the map. The iterator will give you a pair<A, B>. Add each second value to the result list.
You can't just "get" such a list because there is no pre-existing list stored anywhere in the guts, but you can build one:
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 );
}
Or if you really like the more STL way:
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());
One of many "built-in" ways is of course the most obvious one. Just iterate over all pair elements, which are ordered by key (pair::first), and add the value (pair::second) to a new container, which you can construct with the correct capacity to get rid of excess allocations during the iteration and adding.
Just a note: std::list is seldom the container you actually want to be using. Unless, of course, you really, really do need its specific features.
Sure.
std::list<B> list;
std::for_each(myMap.begin(), myMap.end(), [&](const std::pair<const A, B>& ref) {
list.push_back(ref.second);
});
If you don't have a C++0x compiler, first you have my sympathies, and second, you will need to build a quick function object for this purpose.
You can use boost's 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;
}

Copy map values to vector in STL [duplicate]

This question already has answers here:
How to retrieve all keys (or values) from a std::map and put them into a vector?
(24 answers)
Closed 1 year ago.
Working my way through Effective STL at the moment. Item 5 suggests that it's usually preferable to use range member functions to their single element counterparts. I currently wish to copy all the values in a map (i.e. - I don't need the keys) to a vector.
What is the cleanest way to do this?
You could probably use std::transform for that purpose. I would maybe prefer Neils version though, depending on what is more readable.
Example by xtofl (see comments):
#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) );
}
Very generic, remember to give him credit if you find it useful.
You can't easily use a range here because the iterator you get from a map refers to a std::pair, where the iterators you would use to insert into a vector refers to an object of the type stored in the vector, which is (if you are discarding the key) not a pair.
I really don't think it gets much cleaner than the obvious:
#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 );
}
}
which I would probably re-write as a template function if I was going to use it more than once. Something like:
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 );
}
}
With C++11 we have the fancy new for loop:
for (const auto &s : schemas)
names.push_back(s.second);
where schemas is a std::map and names is an std::vector.
This populates the array (names) with values from the map (schemas); change s.second to s.first to get an array of keys.
#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;}
);
Sorry that I didn't add any explanation - I thought that code is so simple that is doesn't require any explanation.
So:
transform( beginInputRange, endInputRange, outputIterator, unaryOperation)
this function calls unaryOperation on every item from inputIterator range (beginInputRange-endInputRange). The value of operation is stored into outputIterator.
If we want to operate through whole map - we use map.begin() and map.end() as our input range. We want to store our map values into vector - so we have to use back_inserter on our vector: back_inserter(your_values_vector). The back_inserter is special outputIterator that pushes new elements at the end of given (as paremeter) collection.
The last parameter is unaryOperation - it takes only one parameter - inputIterator's value. So we can use lambda:
[](auto &kv) { [...] }, where &kv is just a reference to map item's pair. So if we want to return only values of map's items we can simply return kv.second:
[](auto &kv) { return kv.second; }
I think this explains any doubts.
If you are using the boost libraries, you can use boost::bind to access the second value of the pair as follows:
#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) );
}
This solution is based on a post from Michael Goldshteyn on the boost mailing list.
Using lambdas one can perform the following:
{
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); });
}
Here is what I would do.
Also I would use a template function to make the construction of select2nd easier.
#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)
);
}
One way is to use 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);
}
Why not:
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;
}
usage:
auto vec = MapValuesAsVector(anymap);
I thought it should be
std::transform( map.begin(), map.end(),
std::back_inserter(vec),
boost::bind(&MapT::value_type::first,_1) );
We should use the transform function from STL algorithm, the last parameter of transform function could be a function object, function pointer or a lambda function that convert item of map to item of vector. This case map have items have type pair that need to convert to item that has int type for vector. Here is my solution that I use lambda function:
#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;
});
The other answers mention std::transform, and semantically it's the right choice. But in practice std::accumulate might fit better for this task, because:
it allows adding const to the resulting vector;
it just looks nicer, truly functional-style.
Example (using C++17 syntax):
#include <numeric> // for std::accumulate. Note that it's not in <algorithm> where std::transform is located, thanks to Anton Krug for pointing this out
auto map = std::map<int,bool>{};
map[0]=true;
map[1]=false;
const auto mapValues = std::accumulate(map.begin(), map.end(), std::vector<bool>(map.size()), [](auto& vector, const auto& mapEntry) {
vector.push_back(mapEntry.second);
return vector;
});
Surprised nobody has mentioned the most obvious solution, use the std::vector constructor.
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());
}