How to Retrieve All Keys (Or Values) from a Std::Map and Put Them into a Vector

How to retrieve all keys (or values) from a std::map and put them into a vector?

While your solution should work, it can be difficult to read depending on the skill level of your fellow programmers. Additionally, it moves functionality away from the call site. Which can make maintenance a little more difficult.

I'm not sure if your goal is to get the keys into a vector or print them to cout so I'm doing both. You may try something like this:

std::map<int, int> m;
std::vector<int> key, value;
for(std::map<int,int>::iterator it = m.begin(); it != m.end(); ++it) {
key.push_back(it->first);
value.push_back(it->second);
std::cout << "Key: " << it->first << std::endl();
std::cout << "Value: " << it->second << std::endl();
}

Or even simpler, if you are using Boost:

map<int,int> m;
pair<int,int> me; // what a map<int, int> is made of
vector<int> v;
BOOST_FOREACH(me, m) {
v.push_back(me.first);
cout << me.first << "\n";
}

Personally, I like the BOOST_FOREACH version because there is less typing and it is very explicit about what it is doing.

Get map from map by vector of keys

I know I could iterate over the vector, but this doesn't make much of a difference, or does it?

It does make a difference, because iterating in order is typically faster for a vector than for a map (vectors data is local in memory, a maps elements are not) and finding an element is faster in a map than in a vector (O(log(N)) vs O(N) for an unsorted vector).

Lets say you have M elements in the map and N keys in the vector, then your approach is O( M * N) while swapping iteration and finding would be only O( N * log(M)). This only takes into account the complexity for find. Taking into account the iteration is more involved as it very much depends on cache.

Otherwise, I think your approach is fine. I am not aware of an algorithm that would make your code more concise or expressive.

PS you might consider this as a nitpick on wording, but as it happens too often that one overthinks a problem I will mention it: "a smarter way" is not always "a better way". Dont try to be too smart. Most algorithms can be replaced by a simple loop, but often they are considered more expressive and readable than the handwritten loop. Trying to squeeze something into algorithms when there is no algorithm for the problem at hand, often results in less readable and less expressive code. If someone finds an algorithm that can be used here, I'll take back everything in this PS :P

subset std::map into std::vector<std::map> of predefined length

IMHO “the rest” is poorly defined, because (e.g.) splitting 20 elements into 11 parts would yield 10 parts with 1 element each and a “rest” with 10 elements, which is (sort of) ugly if the splitting should be uniform. I would instead use 9 parts with 2 elements in each and then 2 “rests” with 1 element in each. But that’s just a (early) side note; you can tweak this all you like.

The important part is probably the iterator. Well, because you are removing elements from and inserting elements into the same type of map, your best bet is extract() and its counterpart, the overload of insert() that takes nodes. The beauty of this is that the type(s) you use in the map do not need to support move-semantics at all in this case; the entire node remains in existence and therefore nothing needs to be moved. No move_iterator is involved here either — that would only matter if we dereferenced the iterator, which we don’t do.

First let’s define the map splitting (node transfer) for any map-like type and for any vector-like type, simply because we can:

template<template<typename ... S> class R,
template<typename ... A> class C,
typename I,
typename ... S, typename ... A>
void
transfer_segments(C<A...> &source, I &it,
size_t n_segs, const size_t seg_size,
R<C<A...>, S...> &sink) {
for (; n_segs; --n_segs) {
auto &seg{sink.emplace_back()};
for (size_t i{0}; i < seg_size; ++i)
seg.insert(source.extract(it++));
}
}

template<template<typename ... S> class R,
template<typename ... A> class C,
typename ... S, typename ... A>
void
split_container(C<A...> &&source, const size_t n_segs,
R<C<A...>, S...> &sink) {
const size_t seg_leftover{source.size() % n_segs};
const size_t seg_size{source.size() / n_segs};
auto it{source.begin()};
transfer_segments(source, it, seg_leftover, seg_size + 1, sink);
transfer_segments(source, it, n_segs - seg_leftover, seg_size, sink);
}

These templates could gain (much needed) extra type-safety using C++20 concepts, but this is omitted for the sake of brevity. Next we can test the solution on your data and types:

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

namespace { /* ... magic templates from above go here ... */ }

int main() {
static const auto get_map{
[]() -> std::map<std::string, std::string> {
using namespace std::string_literals;
return {{"Red"s, "Red"s},
{"Blue"s, "Blue"s},
{"Green"s, "Green"s},
{"Fuchsia"s, "Fuchsia"s},
{"Mauve"s, "Mauve"s},
{"Gamboge"s, "Gamboge"s},
{"Vermillion"s, "Vermillion"s}};
}};

for (size_t n_segs{1}; n_segs <= 7; ++n_segs) {
std::cout << n_segs << ": {\n";
std::vector<std::map<std::string, std::string>> segs;
split_container(get_map(), n_segs, segs);
for (const auto &seg : segs) {
std::cout << " (";
for (const auto &[k, v] : seg)
std::cout << " [" << k << ':' << v << ']';
std::cout << " )\n";
}
std::cout << " }\n";
}
}

And the output is:

1: {
( [Blue:Blue] [Fuchsia:Fuchsia] [Gamboge:Gamboge] [Green:Green] [Mauve:Mauve] [Red:Red] [Vermillion:Vermillion] )
}
2: {
( [Blue:Blue] [Fuchsia:Fuchsia] [Gamboge:Gamboge] [Green:Green] )
( [Mauve:Mauve] [Red:Red] [Vermillion:Vermillion] )
}
3: {
( [Blue:Blue] [Fuchsia:Fuchsia] [Gamboge:Gamboge] )
( [Green:Green] [Mauve:Mauve] )
( [Red:Red] [Vermillion:Vermillion] )
}
4: {
( [Blue:Blue] [Fuchsia:Fuchsia] )
( [Gamboge:Gamboge] [Green:Green] )
( [Mauve:Mauve] [Red:Red] )
( [Vermillion:Vermillion] )
}
5: {
( [Blue:Blue] [Fuchsia:Fuchsia] )
( [Gamboge:Gamboge] [Green:Green] )
( [Mauve:Mauve] )
( [Red:Red] )
( [Vermillion:Vermillion] )
}
6: {
( [Blue:Blue] [Fuchsia:Fuchsia] )
( [Gamboge:Gamboge] )
( [Green:Green] )
( [Mauve:Mauve] )
( [Red:Red] )
( [Vermillion:Vermillion] )
}
7: {
( [Blue:Blue] )
( [Fuchsia:Fuchsia] )
( [Gamboge:Gamboge] )
( [Green:Green] )
( [Mauve:Mauve] )
( [Red:Red] )
( [Vermillion:Vermillion] )
}

When it comes to a different kind of splitting into uniform parts and “the rest”, the algorithm can be easily adjusted.

Copy map values to vector in STL

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

Inserting into Map of String keys and Vector values

If the string in jsonLabel already exists as a key in the map, then insert will not insert anything into the map.

And the map insert function is to insert into the map itself. The pair should be a pair of the key and value types (where the value should be a vector of doubles).

What you seem to want is simply

myMap[jsonLabel].push_back(latestDouble);

The operator[] function will create a default-constructed value if the key doesn't exist, and as such will create an empty vector for you.



Related Topics



Leave a reply



Submit