Adding all values of map using std::accumulate - c++

I am simply trying to add values of a map defined in the program below:
std::map<int, int> floor_plan;
const size_t distance = std::accumulate(std::begin(floor_plan), std::end(floor_plan), 0);
std::cout << "Total: " << distance;
I get the following error:
Error C2893: Failed to specialize function template 'unknown-type std::plus::operator ()(_Ty1 &&,_Ty2 &&) const'

std::begin(floor_plan) gives you an iterator pointing at std::map<int, int>::value_type which is std::pair<const int, int>. Since there is no operator+ defined for this pair type and an integer, your code fails to compile.
Option #1
If you want to sum up all the mapped values from floor_plan, you'd need to provide your own binary operator that is able to extract the second element of a dereferenced iterator passed in:
std::accumulate(std::begin(floor_plan)
, std::end(floor_plan)
, 0
, [] (int value, const std::map<int, int>::value_type& p)
{ return value + p.second; }
);
DEMO 1
Option #2
Alternatively, you could exploit the Boost.Iterator library to extract the second element of a pair on the fly with boost::make_transform_iterator:
#include <boost/iterator/transform_iterator.hpp>
#include <functional>
auto second = std::mem_fn(&std::map<int, int>::value_type::second);
std::accumulate(boost::make_transform_iterator(std::begin(floor_plan), second)
, boost::make_transform_iterator(std::end(floor_plan), second)
, 0);
DEMO 2
Option #3
Another approach is to use the Boost.Range library along with its own implementation of the accumulate algorithm:
#include <boost/range/numeric.hpp>
#include <boost/range/adaptor/map.hpp>
boost::accumulate(floor_plan | boost::adaptors::map_values, 0);
DEMO 3

Piotr S. answer is right, but if this is not a one-time task, you better make a simple convenient functor for such tasks:
struct AddValues
{
template<class Value, class Pair>
Value operator()(Value value, const Pair& pair) const
{
return value + pair.second;
}
};
const size_t distance = std::accumulate(plan.begin(), plan.end(), 0, AddValues());
Thank to templated operator() you can use this functor for any map in your code. This is much like transparent comparator, but this is transparent "summator".

I will show you not only how does it works.
accumulate Possible implementation as below(as we may sum from a base value, so there is a init value):
template<class InputIt, class T, class BinaryOperation>
T accumulate(InputIt first, InputIt last, T init,
BinaryOperation op)
{
for (; first != last; ++first) {
init = op(std::move(init), *first); // std::move since C++20
}
return init;
}
So when we wants to get sum/product of a vector, it may like this:
vector<int> vec(5);
std::iota(vec.begin(), vec.end(), 1);
cout<<"vec: ";// output vec
std::copy(vec.begin(), vec.end(), std::ostream_iterator<int>(cout, ", "));
// vec: 1, 2, 3, 4, 5,
cout<<"\n vec sum is: "<<accumulate(vec.begin(), vec.end(), 0)<<endl;
// vec sum is: 15
cout<<"vec product is: "<<accumulate(vec.begin(), vec.end(), 1, std::multiplies<int>())<<endl;
// vec product is: 120
As to std::map, you wants to sum the second value of an map, so you have to get each second item in map. So you should get the value_type in map and then get the second item. value_type in map is defined as below:
template <typename Key, typename Value, class Compare = std::less<Key>>
class map{
// using re_tree to sort
typedef Key key_type;
// rb_tree value type
typedef std::pair<key_type, value_type> value_type;
};
For example, get the sum of all the second/first value:
typedef map<string, int> IdPrice;
IdPrice idPrice = {{"001", 100}, {"002", 300}, {"003", 500}};
int sum = accumulate(idPrice.begin(), idPrice.end(), 0, [](int v, const IdPrice::value_type& pair){
return v + pair.second;
// if we want to sum the first item, change it to
// return v + pair.first;
});
cout<<"price sum is: "<<sum<<endl; // price sum is: 900
The para v in the above lambda funtion, stores the tmp sum, with init value 0.

Alternatively, you could use lambda expression with pair<int,int> as the binary operation.
distance = std::accumulate(std::begin(floor_plan), std::end(floor_plan), 0,
[](int value, pair<int,int> p) { return value + p.second; });

Here is a simple example :
#include <iostream>
#include <map>
#include <numeric>
int main() {
// Create a map with some initial key-value pairs
std::map<std::string, int> m = {{"a", 1}, {"b", 2}, {"c", 3}};
// Use std::accumulate to add up all of the values in the map
int sum = std::accumulate(m.begin(), m.end(), 0,
[](int total, const std::pair<std::string, int>& p) {
return total + p.second;
});
// Print the sum of the values in the map
std::cout << "The sum of the values in the map is " << sum << "\n";
return 0;
}

Related

Delete element with specified key and value from std::multimap

Suppose I know that a given std::multimap has exactly one element with a given key and value, and I want to delete this element.
I could explicitly write a std::multimap::find to find some element with that key, then walk backwards until I reach the first element with a different key, walk forward until I find the element I want, and delete it.
Question: Is there anything in <algorithm> or elsewhere that will do this for me? Or do I have to write my own method?
EDIT: This is not the same question as STL Multimap Remove/Erase Values, which is about removing all elements with a given value.
There is no built in way to do anything involving searching by key and value but as NathanOliver says in comments, you can write a helper function on top of multimap::equal_range, e.g.
#include <map>
#include <iostream>
template<typename K, typename V>
typename std::multimap<K, V>::const_iterator find_item_by_key_and_value(const std::multimap<K, V>& mm, K k, V v) {
auto range = mm.equal_range(k);
return std::find_if(range.first, range.second, [v](const auto& p) {return p.second == v; });
}
template<typename K, typename V>
void erase_item_by_key_and_value( std::multimap<K, V>& mm, K k, V v) {
auto iter = find_item_by_key_and_value(mm, k, v);
if (iter != mm.end())
mm.erase(iter);
}
int main()
{
std::multimap<int, int> mm = {
{1,2}, {2,42}, {2,54}, {2, 37}, {42,42}
};
erase_item_by_key_and_value(mm, 2, 37);
for (const auto& [k, v] : mm) {
std::cout << "{" << k << " , " << v << "}\n";
}
}

std::reduce with std::unordered_map

I have an unordered_map of vectors and I'm trying to use std::reduce to get the sum of all values in all vectors in the map. My current functional code (which I want to replace) looks like this:
// input is std::unordered_map<std::vector<uint64_t>>
template<typename T>
uint64_t get_map_sum(T& my_map)
{
uint64_t totalcount = 0;
for (auto& p : my_map)
{
for (const auto& q : p.second)
totalcount += q;
}
return total_count;
}
I'd like to replace this with std::reduce to utilize the parallel execution; I thought this would be straight forward as I only needed to replace each loop with a call to std::reduce, but this doesn't appear to be working. My attempt is this:
#include <numeric>
#include <execution>
#include <vector>
#include <unordered_map>
#include <cstdint>
// reduces the vectors
template <typename Iter, typename T>
T get_vector_sum(Iter begin, Iter end, T initial = 0)
{
return std::reduce(std::execution::par_unseq, begin, end, initial,
[&](auto cur, auto prev) { return cur + prev; });
}
// calls get_vector_sum for all vectors and then reduces vector sums
template<typename Iter>
uint64_t get_map_sum(Iter begin, Iter end)
{
return std::reduce(std::execution::par_unseq, begin, end, 0ULL,
[&](auto prev, auto cur)
{
return get_vector_sum<std::vector<uint64_t>::iterator,
uint64_t>(cur.begin(), cur.end(), prev);
//return get_vector_sum<std::vector<uint64_t>::iterator,
// uint64_t>(cur.second.begin(), cur.second.end(), prev);
});
}
With the code above, I get an error message saying error C2039: 'begin': is not a member of 'std::pair' referring to the auto cur in the lambda inside get_map_sum. I initially used cur as a std::pair, but when I did that I got a different error saying error C2228: left of '.second' must have class/struct/union.
int main()
{
std::unordered_map<uint64_t, std::vector<uint64_t>> in({
{1, std::vector<uint64_t>{1,2,3,4,5} },
{2, std::vector<uint64_t>{1,2,3,4,5}},
{3, std::vector<uint64_t>{1,2,3,4,5}}});
auto x = get_map_sum(in); // output 45
auto y = get_map_sum(in.begin(), in.end()); // error
return 0;
}
Is it possible to use std::reduce with maps like this and, if so, what changes do I need to make to get this working?
Note this requirements for binary_op of std::reduce:
binary FunctionObject that will be applied in unspecified order to the result of dereferencing the input iterators, the results of other binary_op and init.
This implies that the result of your lambda result and init needs to be of the same type as map's value type, i.e., std::pair<const uint64_t, std::vector<uint64_t>>.
You would therefore need to perform the outer reduction over values of this type, which would involve construction of new vectors.
I have also tried to create an exemplary code as follows:
using M = std::unordered_map<uint64_t, std::vector<uint64_t>>;
using V = M::value_type;
M in({ {1, std::vector<uint64_t>{1,2,3,4,5}},
{2, std::vector<uint64_t>{1,2,3,4,5}},
{3, std::vector<uint64_t>{1,2,3,4,5}} });
auto p = std::reduce(in.begin(), in.end(), V{},
[](const V& a, const V& b) {
auto ra = std::reduce(a.second.begin(), a.second.end(), 0UL,
[](uint64_t i1, uint64_t i2){ return i1 + i2; });
auto rb = std::reduce(b.second.begin(), b.second.end(), 0UL,
[](uint64_t i1, uint64_t i2){ return i1 + i2; });
return V{0, { ra + rb }};
});
But it does not compile with GCC due to seemingly missing std::reduce implementation and Clang complains about missing copy assignment operator for value type, which is not copy-assignable due to const key: https://wandbox.org/permlink/FBYAhCArtOHvwu8C.
However, in cppreference, the requirements for the value type is only MoveConstructible, not Copy/MoveAssignable. So, there seems to be an incorrect implementation in libc++.
In this exemplary code, I was able to make it working by defning V without const as follows:
using V = std::pair<uint64_t, std::vector<uint64_t>>;
See https://wandbox.org/permlink/lF9VuJwISYXhpBJL.
Rather than constructing vectors as the intermediate result, we just need to provide a type implicitly convertible from M::value_type.
using M = std::unordered_map<uint64_t, std::vector<uint64_t>>;
template <typename Iter, typename T>
T par_unseq_sum(Iter begin, Iter end, T initial = 0)
{
// std::plus is the default reducer
return std::reduce(std::execution::par_unseq, begin, end, initial);
}
class map_vector_sum
{
public:
map_vector_sum() : sum(0) {}
map_vector_sum(M::const_reference elem) : sum(par_unseq_sum(elem.second)) {}
map_vector_sum& operator+(const map_vector_sum & rhs) { sum += rhs.sum; }
explicit operator uint64_t() { return sum; }
private:
uint64_t sum;
}
M in({ {1, std::vector<uint64_t>{1,2,3,4,5}},
{2, std::vector<uint64_t>{1,2,3,4,5}},
{3, std::vector<uint64_t>{1,2,3,4,5}} });
uint64_t sum = par_unseq_sum(in.begin(), in.end(), map_vector_sum());

std::find_if in a multimap returns error with a functor

In the following code snippet, I try to find values in a multimap that are equal to the value of myPairA.second which correspond to int f = 0. However in the std::find_if STL algorithm, this shows an error :
/usr/include/c++/5/bits/predefined_ops.h:234:30: error: no match for call to ‘(EqualFunctor<int>) (std::pair<const int, int>&)’
{ return bool(_M_pred(*__it)); }
^`
multimaps_2.cpp:12:10: note: candidate: bool EqualFunctor<T>::operator()(std::pair<const int, T*>) [with T = bool operator() (std::pair<const int, T*> myPair)
Here's my program: (the line with the std::find_if creates an error)
See 2nd version below
#include <iostream>
#include <algorithm>
#include <iterator>
#include <map>
template <typename T>
class EqualFunctor
{
T *t_;
public:
EqualFunctor(T *t) : t_(t) {}
bool operator() (std::pair<const int, T*> myPair)
{ return myPair.second == t_; }
};
int main()
{
// h, i & j are duplicates of f and g
int f = 0, g = 1,
h = 0, i = 1, j = 1;
// declare five pairs
std::pair<const int, int> myPairA (1, f),
myPairB (2, g),
myPairC (3, h),
myPairD (4, i),
myPairE (5, j);
std::multimap<int, int> myMultimap;
// insert pairs above in multimap with the exception of myPairA
myMultimap.insert(myPairB);
myMultimap.insert(myPairC);
myMultimap.insert(myPairD);
myMultimap.insert(myPairE);
std::multimap<int, int>::iterator it;
// pointer to f = 0, since the EqualFunctor class accepts a pointer
int *ptrMyPairA = &myPairA.second;
// find in multimap the pair that is equal to f, ie myPairA.second
// with the EqualFunctor class
// Problem is here
it = std::find_if(myMultimap.begin(), myMultimap.end(),
EqualFunctor<int>(ptrMyPairA));
// print to screen
std::cout << (*it).second << std::endl;
return 0;
}
The desired output would be to show 0 at the screen which corresponds to the first occurrence of a duplicate in the multimap. (myPairC.second which is equal to int h = 0)
I've tried to read other posts related to this stackoverflow question but it hasn't helped me solve it.
Also my question is almost identical to this one on stackoverflow but it still
doesn't help solving the issue.
Thanks
EDIT:
changing std::pair<const int, int> to std::pair<const int, int*> still gives an error:
#include <iostream>
#include <algorithm>
#include <iterator>
#include <map>
template <typename T>
class EqualFunctor
{
T *t_;
public:
EqualFunctor(T *t) : t_(t) {}
bool operator() (std::pair<const int, T*> myPair)
{ return myPair.second == t_; }
};
int main()
{
// h, i & j are duplicates of f and g
int f = 0, g = 1,
h = 0, i = 1, j = 1;
int *ptrF = &f, *ptrG = &g,
*ptrH = &h, *ptrI = &i, *ptrJ = &j;
// declare five pairs
std::pair<const int, int*> myPairA (1, ptrF),
myPairB (2, ptrG),
myPairC (3, ptrH),
myPairD (4, ptrI),
myPairE (5, ptrJ);
std::multimap<int, int> myMultimap;
// insert pairs above in multimap with the exception of myPairA
myMultimap.insert(myPairB);
myMultimap.insert(myPairC);
myMultimap.insert(myPairD);
myMultimap.insert(myPairE);
std::multimap<int, int>::iterator it;
// find in multimap the pair that is equal to f, ie myPairA.second
// with the EqualFunctor class
// Problem is here
it = std::find_if(myMultimap.begin(), myMultimap.end(),
EqualFunctor<int>(myPairA.second));
// print to screen
std::cout << (*it).second << std::endl;
return 0;
}
gives an error no viable overloaded '=' on the line where std::find_if is.
0x499602D2 already explained the problem in the comment, so please wait if he posts an answer before accepting any other replay.
The element type of the map isn't pair<const int, int*>,
it's pair<const int, int> as you have written.
Your functor takes the former which is why it doesn't work.
You can find the fixed code on Wandbox. I decided to post an answer to show the fixed code, and additionally how the code can be simplified using brace initialization, lambda, auto and constructor deduction:
#include <iostream>
#include <algorithm>
#include <iterator>
#include <map>
template <typename K, typename V>
class EqualFunctor
{
V t_;
public:
EqualFunctor(V t) : t_(t) {}
bool operator() (std::pair<K const, V> const& myPair)
{ return myPair.second == t_; }
};
int main()
{
// use C++17 constructor deduction
auto const myPairA = std::pair(1, 0);
auto const myMultimap = std::multimap<int,int>{ {2,1}, {3,0}, {4,1}, {5,1}};
// find in multimap the pair that is equal to f, ie myPairA.second
// with the EqualFunctor class
// Problem is here
auto it = std::find_if(myMultimap.begin(), myMultimap.end(),
EqualFunctor<int,int>(myPairA.second));
// print to screen
std::cout << it->second << std::endl;
// simpler with lambda
it = std::find_if(myMultimap.begin(), myMultimap.end(),
[&myPairA](auto const& x) {return x.second == myPairA.second;} );
// print to screen
std::cout << it->second << std::endl;
return 0;
}

Efficient way to find frequencies of each unique value in the std::vector

Given a vector std::vector<double> v, we can find unique elements efficiently by:
std::vector<double> uv(v.begin(), v.end());
std::sort(uv.begin(), uv.end());
std::erase(std::unique(uv.begin, uv.end()), uv.end());
What would the be the nicest way (without loops, with STL or lambdas) to create a vector:
std::vector<double> freq_uv(uv.size());
which would contain frequencies of each distinct element appearing in v (order the same as sorted unique values)?
Note: type can be anything, not just double
After you sort, before you erase:
std::vector<int> freq_uv;
freq_uv.push_back(0);
auto prev = uv[0]; // you should ensure !uv.empty() if previous code did not already ensure it.
for (auto const & x : uv)
{
if (prev != x)
{
freq_uv.push_back(0);
prev = x;
}
++freq_uv.back();
}
Note that, while I generally like to count occurences with a map, as Yakk is doing, in this case I think it is doing a lot of unnecessary work as we already know the vector is sorted.
Another possibility is to use a std::map (not unordered), instead of sorting. This will get your frequencies first. Then, since the map is ordered, you can just create the sorted, unique vector, and the frequency vector directly from the map.
// uv not yet created
std::map<T, int> freq_map;
for (auto const & x : v)
++freq_map[x];
std::vector<T> uv;
std::vector<int> freq_uv;
for (auto const & p : freq_map)
{
uv.push_back(p.first);
freq_uv.push_back(p.second);
}
First, note that == and to a lesser extent < on double is often a poor idea: often you'll have values that logically "should" be equal if the double was infinite precision, but are slightly different.
However, collecting the frequencies is easy:
template<typename T, typename Allocator>
std::unordered_map< T, std::size_t > frequencies( std::vector<T, Allocator> const& src ) {
std::unordered_map< T, std::size_t > retval;
for (auto&& x:src)
++retval[x];
return retval;
}
assuming std::hash<T> is defined (which it is for double). If not, there is more boilerplate, so I'll skip it. Note that this does not care if the vector is sorted.
If you want it in the form of std::vector<std::size_t> in sync with your sorted vector, you can just do this:
template<typename T, typename Hash, typename Equality, typename Allocator>
std::vector<std::size_t> collate_frequencies(
std::vector<T, Allocator> const& order,
std::unordered_map<T, std::size_t, Hash, Equality> const& frequencies
) {
std::vector<std::size_t> retval;
retval.reserve(order.size());
for( auto&& x : order )
retval.push_back( frequencies[x] );
return retval;
}
I took the liberty of making these functions overly generic, so they support more than just doubles.
using equal_range:
std::vector<int> results;
for(auto i = begin(v); i != end(v);)
{
auto r = std::equal_range(i, end(v), *i);
results.emplace_back( std::distance(r.first, r.second) );
i = r.second;
}
SSCCE:
#include <vector>
#include <algorithm>
#include <iostream>
#include <iterator>
int main()
{
std::vector<double> v{1.0, 2.0, 1.0, 2.0, 1.0, 3.0};
std::sort(begin(v), end(v));
std::vector<int> results;
for(auto i = begin(v); i != end(v);)
{
auto r = std::equal_range(i, end(v), *i);
results.emplace_back( std::distance(r.first, r.second) );
i = r.second;
}
for(auto const& e : results) std::cout << e << "; ";
}
An O(n) solution when the range of values is limited, for example chars. Using less than the CPU level 1 cache for the counter leaves room for other values.
(untested code)
constexp int ProblemSize = 256;
using CountArray = std::array<int, ProblemSize>;
CountArray CountUnique(const std::vector<char>& vec) {
CountArray count;
for(const auto ch : vec)
count[ch]++;
return count;
}

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