Iterator Adapter to Iterate Just the Values in a Map

iterator adapter to iterate just the values in a map?

I don't think there's anything out of the box. You can use boost::make_transform.

template<typename T1, typename T2> T2& take_second(const std::pair<T1, T2> &a_pair) 
{
return a_pair.second;
}

void run_map_value()
{
map<int,string> a_map;
a_map[0] = "zero";
a_map[1] = "one";
a_map[2] = "two";
copy( boost::make_transform_iterator(a_map.begin(), take_second<int, string>),
boost::make_transform_iterator(a_map.end(), take_second<int, string>),
ostream_iterator<string>(cout, "\n")
);
}

Can I easily iterate over the values of a map using a range-based for loop?

The magic lies with Boost.Range's map_values adaptor:

#include <boost/range/adaptor/map.hpp>

for(auto&& i : foo | boost::adaptors::map_values){
i->bar();
}

And it's officially called a "range-based for loop", not a "foreach loop". :)

Iterator for C++11 map values (simple and transparent)

it's pretty trivial.

Here's an extremely simplistic version that minimally solves the problem for a map of ints to strings. You can either rewrite for the types you want or templatise it as you wish.

#include <map>
#include <iostream>
#include <iterator>
#include <string>
#include <algorithm>

struct map_value_iterator : public std::map<int, std::string>::const_iterator
{
map_value_iterator(std::map<int, std::string>::const_iterator src)
: std::map<int, std::string>::const_iterator(std::move(src))
{

}

// override the indirection operator
const std::string& operator*() const {
return std::map<int, std::string>::const_iterator::operator*().second;
}
};

using namespace std;

int main()
{
map<int, string> myMap { {1, "Hello" }, { 2, "World" } };

copy(map_value_iterator(begin(myMap)), map_value_iterator(end(myMap)), ostream_iterator<string>(cout , " "));
cout << endl;

return 0;
}

Program output:

Compiling the source code....
$g++ -std=c++11 main.cpp -o demo -lm -pthread -lgmpxx -lgmp -lreadline 2>&1

Executing the program....
$demo
Hello World

Iterate keys in a C++ map

If you really need to hide the value that the "real" iterator returns (for example because you want to use your key-iterator with standard algorithms, so that they operate on the keys instead of the pairs), then take a look at Boost's transform_iterator.

[Tip: when looking at Boost documentation for a new class, read the "examples" at the end first. You then have a sporting chance of figuring out what on earth the rest of it is talking about :-)]

C++ Loop through Map

You can achieve this like following :

map<string, int>::iterator it;

for (it = symbolTable.begin(); it != symbolTable.end(); it++)
{
std::cout << it->first // string (key)
<< ':'
<< it->second // string's value
<< std::endl;
}

With C++11 ( and onwards ),

for (auto const& x : symbolTable)
{
std::cout << x.first // string (key)
<< ':'
<< x.second // string's value
<< std::endl;
}

With C++17 ( and onwards ),

for (auto const& [key, val] : symbolTable)
{
std::cout << key // string (key)
<< ':'
<< val // string's value
<< std::endl;
}

Why doesn’t std::map provide key_iterator and value_iterator?

Yes, it is a silly shortcoming. But it's easily rectified: you can write your own generic key_iterator class which can be constructed from the map (pair) iterator. I've done it, it's only a few lines of code, and it's then trivial to make value_iterator too.

Is it possible to iterate a map, ordered by value?

An std::map sorts its elements according to their keys, either with the key's operator < or a custom comparator. It can't, however, sort itself according to the values.

You may be interested in std::set<std::string>, where the keys are the values (but you lose "direct" indexing), or a simple std::vector<std::string> which you can std::sort.

Is it possible in C++ to do std::map for element : container iteration with named variables (eg, key and value) instead of .first and .second?

An approach inspired by Barry below would be to write a range adapter.

Doing this without boost or similar library support is a pain, but:

  1. Write a range template. It stores 2 class iterators and has begin() and end() methods (and whatever else you want).

  2. Write a transforming iterator adapter. It takes an iterator, and wraps it up so that its value type is transformed by some function object F.

  3. Write a to_kv transformer that takes a std::pair<K, V> cv& and returns a struct kv_t { K cv& key; V cv& value; }.

  4. Wire 3 into 2 into 1 and call it as_kv. It takes a range of pairs, and returns a range of key-values.

The syntax you end up with is:

std::map<int, std::string> m;

for (auto kv : as_kv(m)) {
std::cout << kv.key << "->" << kv.value << "\n";
}

which is nice.

Here is a minimalist solution that doesn't actually create legal iterators, but does support for(:):

template<class Key, class Value>
struct kv_t {
Key&& key;
Value&& value;
};

// not a true iterator, but good enough for for(:)
template<class Key, class Value, class It>
struct kv_adapter {
It it;
void operator++(){ ++it; }
kv_t<Key const, Value> operator*() {
return {it->first, it->second};
}
friend bool operator!=(kv_adapter const& lhs, kv_adapter const& rhs) {
return lhs.it != rhs.it;
}
};
template<class It, class Container>
struct range_trick_t {
Container container;
range_trick_t(Container&&c):
container(std::forward<Container>(c))
{}
It begin() { return {container.begin()}; }
It end() { return {container.end()}; }
};
template<class Map>
auto as_kv( Map&& m ) {
using std::begin;
using iterator = decltype(begin(m)); // no extra (())s
using key_type = decltype((begin(m)->first)); // extra (())s on purpose
using mapped_type = decltype((begin(m)->second)); // extra (())s on purpose
using R=range_trick_t<
kv_adapter<key_type, mapped_type, iterator>,
Map
>;
return R{std::forward<Map>(m)};
}
std::map<int, std::string> m() { return {{0, "Hello"}, {2, "World"}}; }

which is very minimal, but works. I would not generally encourage this kind of half-assed pseudo iterators for for(:) loops; using real iterators is only a modest additional cost, and doesn't surprise people later on.

live example

(Now with temporary map support. Does not support flat C arrays ... yet)

The range-trick stores a container (possibly a reference) in order to copy temporary containers into the object stored for the duration of the for(:) loop. Non-temporary containers the Container type is a Foo& of some kind, so it doesn't make a redundant copy.

On the other hand, kv_t obviously only stores references. There could be a strange case of iterators returning temporaries that break this kv_t implementation, but I'm uncertain how to avoid it in general without sacrificing performance in more common cases.


If you don't like the kv. part of the above, we can do some solutions, but they aren't as clean.

template<class Map>
struct for_map_t {
Map&& loop;
template<class F>
void operator->*(F&& f)&&{
for (auto&& x:loop) {
f( decltype(x)(x).first, decltype(x)(x).second );
}
}
};
template<class Map>
for_map_t<Map> map_for( Map&& map ) { return {std::forward<Map>(map)}; }

then:

map_for(m)->*[&](auto key, auto& value) {
std::cout << key << (value += " ") << '\n';
};

close enough?

live example

There are some proposals around first-class tuples (and hence pairs) that may give you something like that, but I do not know the status of the proposals.

The syntax you may end up if this gets into C++ would look something like this:

for( auto&& [key, value] : container )

Comments on the ->* abomination above:

So the ->* is being used sort of as an operator bind from Haskell (together with implicit tuple unpacking), and we are feeding it a lambda that takes the data contained within the map and returns void. The (Haskell-esque) return type becomes a map over void (nothing), which I elide into void.

The technique has a problem: you lose break; and continue; which suck.

A less hackey Haskell-inspired variant would expect the lambda to return something like void | std::experimental::expected<break_t|continue_t, T>, and if T is void return nothing, if T is a tuple-type return a map, and if T is a map join the returned map-type. It would also either unpack or not unpack the contained tuple depending on what the lambda wants (SFINAE-style detection).

But that is a bit much for a SO answer; this digression points out that the above style of programming isn't a complete dead-end. It is unconventional in C++ however.

How to iterate over a C++ STL map data structure using the 'auto' keyword?

This code uses 2 new features from C++11 standard the auto keyword, for type inference, and the range based for loop.

Using just auto this can be written as (thanks Ben)

for (auto it=mymap.begin(); it!=mymap.end(); ++it)

Using just range for this can be written as

for (std::pair<const char,int>& x: mymap) {
std::cout << x.first << " => " << x.second << '\n';
}

Both of these do the exact same task as your two versions.

STL like iterator over a collection of hash maps

You could use boost iterator facade, that will help you with the task of implementing custom iterators. The idea would be:

1-maintain a reference to the vector containing the maps (levels_).

2-a iterator indicating what element of the previous vector the custom iterator is iterating (of type std::vector<MapPtr>::iterator or std::vector<MapPtr>::const_iterator) or a index with the same info (to retrieve the end of level_[index]).

3-a iterator with current element of the iteration of the previous iterator (the actual element of the iteration).

Some sample code:

#include <boost/iterator/iterator_facade.hpp>

namespace impl
{
template <class Value>
class iterator
: public boost::iterator_facade<
config_iterator<Value>
, Value
, boost::forward_traversal_tag
>
{
public:
config_iterator() {...}
explicit config_iterator(parameters) { /*your specific contructor*/ }

private:
template <class OtherValue>
config_iterator(config_iterator<OtherValue> const& other);

friend class boost::iterator_core_access;
template <class> friend class config_iterator;

template <class OtherValue>
bool equal(config_iterator<OtherValue> const& other) const { } // Verify is two iterators are equals (used to verify if it == end)

void increment() {} // Logic for incrementing the iterator
Value& dereference() const {} // Returning the actual value

// members
};
}

typedef impl::iterator<type> iterator;

This is a template file for very simple iterator (forward), read the Iterator Help for more info, the same can be implementing overloading the right operators (++ post a pre increment, *, ->, etc...), by boost provide a ways of defining the minimum necessary to implement the rest.



Related Topics



Leave a reply



Submit