2

I want to create a std::vector<char> with something like: v(map.begin(), map.end()); rather than iterating over all elements of the map and resizing v over and over.

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

int main() {
        std::map<int, char> map{{1,'a'},{2,'b'},{3,'c'}, {4,'d'}};
        std::vector<char> v;
        for(auto& [ i , c ] : map){
            // std::cout << i << " -> " << c <<"\n";
            v.push_back(c);
        }
}
cigien
  • 57,834
  • 11
  • 73
  • 112
nac001
  • 693
  • 2
  • 9
  • 18
  • 3
    Why not simply [`reserve()`](https://en.cppreference.com/w/cpp/container/vector/reserve), if you don't want to resize? – andreee Dec 28 '21 at 22:45
  • 1
    `std::transform(map.begin(), map.end(), std::back_inserter(v), [](auto const& pr){ return pr.second; });` – WhozCraig Dec 28 '21 at 23:58

3 Answers3

7

In C++20, you could create a view over the values by using std::views::values:

#include <map>
#include <vector>
#include <ranges>

int main() {
    std::map<int, char> map{{1, 'a'}, {2, 'b'}, {3, 'c'}, {4, 'd'}};    
    auto view = std::views::values(map);
    std::vector<char> v(view.begin(), view.end());
}

Demo

A more general purpose view is the std::views::transform where you supply the transformation to be done via a functor:

#include <map>
#include <vector>
#include <ranges>

int main() {
    std::map<int, char> map{{1, 'a'}, {2, 'b'}, {3, 'c'}, {4, 'd'}};    
    auto view = map | std::views::transform([](auto&& p){ return p.second; });
    std::vector<char> v(view.begin(), view.end());
}

Demo

Ted Lyngmo
  • 93,841
  • 5
  • 60
  • 108
1

You can call reserve on the std::vector in order to allocate the memory you need up front and avoid the resizing.

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

int main( )
{
    std::map<int, char> map{{1,'a'},{2,'b'},{3,'c'}, {4,'d'}};
    std::vector<char> v{ };
    v.reserve( map.size( ) );

    std::for_each( std::begin( map ), std::end( map ), 
        [ &v ]( const auto& pair ){ v.push_back( pair.second ); } );
}
WBuck
  • 5,162
  • 2
  • 25
  • 36
0

As mentioned in comments, you can reserve space for your vector to avoid re-allocations. With the tools C++'s for loops now have for destructing things like maps, this is very clean.

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

int main() {
    std::map<int, char> map{{1,'a'},{2,'b'},{3,'c'}, {4,'d'}};
    std::vector<char> v;
    
    v.reserve(map.size());
 
    for (auto& [i, c] : map) v.push_back(c);
    for (auto& i : v) std::cout << i << std::endl;
}
Chris
  • 26,361
  • 5
  • 21
  • 42