Use of for_each on map elements

C++AlgorithmStlStdmapStd Pair

C++ Problem Overview


I have a map where I'd like to perform a call on every data type object member function. I yet know how to do this on any sequence but, is it possible to do it on an associative container?

The closest answer I could find was this: Boost.Bind to access std::map elements in std::for_each. But I cannot use boost in my project so, is there an STL alternative that I'm missing to boost::bind?

If not possible, I thought on creating a temporary sequence for pointers to the data objects and then, call for_each on it, something like this:

class MyClass
{
public:
 void Method() const;
}

std::map<int, MyClass> Map;
//...

std::vector<MyClass*> Vector;
std::transform(Map.begin(), Map.end(), std::back_inserter(Vector), std::mem_fun_ref(&std::map<int, MyClass>::value_type::second));
std::for_each(Vector.begin(), Vector.end(), std::mem_fun(&MyClass::Method));

It looks too obfuscated and I don't really like it. Any suggestions?

C++ Solutions


Solution 1 - C++

C++11 allows you to do:

for (const auto& kv : myMap) {
    std::cout << kv.first << " has value " << kv.second << std::endl;
}

C++17 allows you to do:

for (const auto& [key, value] : myMap) {
    std::cout << key << " has value " << value << std::endl;
}

using structured binding.

UPDATE:

const auto is safer if you don't want to modify the map.

Solution 2 - C++

You can iterate through a std::map object. Each iterator will point to a std::pair<const T,S> where T and S are the same types you specified on your map.

Here this would be:

for (std::map<int, MyClass>::iterator it = Map.begin(); it != Map.end(); ++it)
{
  it->second.Method();
}

If you still want to use std::for_each, pass a function that takes a std::pair<const int, MyClass>& as an argument instead.

Example:

void CallMyMethod(std::pair<const int, MyClass>& pair) // could be a class static method as well
{
  pair.second.Method();
}

And pass it to std::for_each:

std::for_each(Map.begin(), Map.end(), CallMyMethod);

Solution 3 - C++

C++14 brings generic lambdas. Meaning we can use std::for_each very easily:

std::map<int, int> myMap{{1, 2}, {3, 4}, {5, 6}, {7, 8}};

std::for_each(myMap.begin(), myMap.end(), [](const auto &myMapPair) {
    std::cout << "first " << myMapPair.first << " second "
              << myMapPair.second << std::endl;
});

I think std::for_each is sometimes better suited than a simple range based for loop. For example when you only want to loop through a subset of a map.

Solution 4 - C++

How about a plain C++? (example fixed according to the note by @Noah Roberts)

for(std::map<int, MyClass>::iterator itr = Map.begin(), itr_end = Map.end(); itr != itr_end; ++itr) {
  itr->second.Method();
}

Solution 5 - C++

It's unfortunate that you don't have Boost however if your STL implementation has the extensions then you can compose mem_fun_ref and select2nd to create a single functor suitable for use with for_each. The code would look something like this:

#include <algorithm>
#include <map>
#include <ext/functional>   // GNU-specific extension for functor classes missing from standard STL

using namespace __gnu_cxx;  // for compose1 and select2nd

class MyClass
{
public:
    void Method() const;
};

std::map<int, MyClass> Map;

int main(void)
{
    std::for_each(Map.begin(), Map.end(), compose1(std::mem_fun_ref(&MyClass::Method), select2nd<std::map<int, MyClass>::value_type>()));
}

Note that if you don't have access to compose1 (or the unary_compose template) and select2nd, they are fairly easy to write.

Solution 6 - C++

For fellow programmers who stumble upon this question from google, there is a good way using boost.

Explained here : https://stackoverflow.com/questions/2104208/is-it-possible-to-use-boostforeach-with-stdmap

Real example for your convenience :

// typedef in include, given here for info : 
typedef std::map<std::string, std::string> Wt::WEnvironment::CookieMap

Wt::WEnvironment::CookieMap cookie_map = environment.cookies();

BOOST_FOREACH( const Wt::WEnvironment::CookieMap::value_type &cookie, cookie_map )
{
	std::cout << "cookie : " << cookie.first << " = " << cookie.second << endl;
}

enjoy.

Solution 7 - C++

From what I remembered, C++ map can return you an iterator of keys using map.begin(), you can use that iterator to loop over all the keys until it reach map.end(), and get the corresponding value: C++ map

Solution 8 - C++

Will it work for you ?

class MyClass;
typedef std::pair<int,MyClass> MyPair;
class MyClass
{
  private:
  void foo() const{};
public:
static void Method(MyPair const& p) 
{
    //......
        p.second.foo();
};
}; 
// ...
std::map<int, MyClass> Map;
//.....
std::for_each(Map.begin(), Map.end(), (&MyClass::Method));

Solution 9 - C++

Just an example:

template <class key, class value>
class insertIntoVec
{
public:
	insertIntoVec(std::vector<value>& vec_in):m_vec(vec_in)
	{}

	void operator () (const std::pair<key, value>& rhs)  
	{	
		m_vec.push_back(rhs.second);
	}

private:
	std::vector<value>& m_vec;
};

int main()
{
std::map<int, std::string> aMap;
aMap[1] = "test1";
aMap[2] = "test2";
aMap[3] = "test3";
aMap[4] = "test4";

std::vector<std::string> aVec;

aVec.reserve(aMap.size());
std::for_each(aMap.begin(), aMap.end(),
          insertIntoVec<int, std::string>(aVec) 
	);

}

Solution 10 - C++

I wrote this awhile back to do just what you're looking for.

namespace STLHelpers
{
    //
	// iterator helper type for iterating through the *values* of key/value collections
	//

	/////////////////////////////////////////////
	template<typename _traits>
	struct _value_iterator
	{
		explicit _value_iterator(typename _traits::iterator_type _it)
			: it(_it)
		{
		}

		_value_iterator(const _value_iterator &_other)
			: it(_other.it)
		{
		}

		friend bool operator==(const _value_iterator &lhs, const _value_iterator &rhs)
		{
			return lhs.it == rhs.it;
		}

		friend bool operator!=(const _value_iterator &lhs, const _value_iterator &rhs)
		{
			return !(lhs == rhs);
		}

		_value_iterator &operator++()
		{
			++it;
			return *this;
		}

		_value_iterator operator++(int)
		{
			_value_iterator t(*this);
			++*this;
			return t;
		}

		typename _traits::value_type &operator->()
		{
			return **this;
		}

		typename _traits::value_type &operator*()
		{
			return it->second;
		}

		typename _traits::iterator_type it;
	};

	template<typename _tyMap>
	struct _map_iterator_traits
	{
		typedef typename _tyMap::iterator iterator_type;
		typedef typename _tyMap::mapped_type value_type;
	};

	template<typename _tyMap>
	struct _const_map_iterator_traits
	{
		typedef typename _tyMap::const_iterator iterator_type;
		typedef const typename _tyMap::mapped_type value_type;
	};
}

Solution 11 - C++

Here is an example of how you can use for_each for a map.

std::map<int, int> map;

map.insert(std::pair<int, int>(1, 2));
map.insert(std::pair<int, int>(2, 4));
map.insert(std::pair<int, int>(3, 6));

auto f = [](std::pair<int,int> it) {std::cout << it.first + it.second << std::endl; };
std::for_each(map.begin(), map.end(), f);

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionAntonio P&#233;rezView Question on Stackoverflow
Solution 1 - C++SebastianView Answer on Stackoverflow
Solution 2 - C++ereOnView Answer on Stackoverflow
Solution 3 - C++Christian RappView Answer on Stackoverflow
Solution 4 - C++bobahView Answer on Stackoverflow
Solution 5 - C++David JoynerView Answer on Stackoverflow
Solution 6 - C++OffirmoView Answer on Stackoverflow
Solution 7 - C++vodkhangView Answer on Stackoverflow
Solution 8 - C++a1ex07View Answer on Stackoverflow
Solution 9 - C++aJ.View Answer on Stackoverflow
Solution 10 - C++moswaldView Answer on Stackoverflow
Solution 11 - C++HmdRmzView Answer on Stackoverflow