开发者

How to iterate through map of map of map of map of map of map of vector

I am trying to gather all the data from a map of map of map of map of map of map of map of vector without having to have 7 loops in C++.

Here is how the data looks:

Map 1=>Map 1.1=>Map 1.1.1=>Map 1.1.2=>Map 1.1.3=>Map 1.1.4=>Vector 1.1.5=>Elem 1
                                                                        =>Elem 2
       Map 1.2=>Map 1.2.1=>Map 1.2.2=>Map 1.2.3=>Map 1.2.4=>Vector 1.2.5=> Elem 1
                                                                        =>Elem 2
Map 2 =>Map 1.1=>Map 1.1.1=>Map 1.1.2=>Map 1.1.3=>Map 1.1.4=>Vector 1.1.5=>Elem 1
                                                                         =>Elem 2
        Map 1.2=>Map 1.2.1=>Map 1.2.2=>Map 1.2.3=>Map 1.2.4=>Vector 1.2.5=>Elem 1
                                                                         =>Elem 2

So I am trying to collect all the Elem 1, Elem 2 from all the maps into a map.

开发者_如何学编程

Can someone help me do this instead of the obvious loop through each map and leading to 7 loops in C++?

Thanks for the help.

(Update: Wow looking back at this after 10 years, what a code nightmare it was trying to fix someone else's legacy code. Hopefully no needs this now :)


I like @inflagranti's idea - so, without claim to utility, here's a for-each template that iterates over everything. It uses the is_container trait from the pretty printer, which I don't replicate here.

Update: Now fully worked out to deal with both with naked value types and with pair value types.

Update 2: Simplified the implementation class, thanks to @Luc Danton.

#include <algorithm>

#include "prettyprint.hpp"    
using namespace pretty_print;  // for "is_container" trait

template <typename T> struct is_pair : public std::false_type { };
template <typename S, typename T> struct is_pair<std::pair<S,T>> : public std::true_type { };

template <typename T> struct final_value { typedef T type; };
template <typename S, typename T> struct final_value<std::pair<S,T>> { typedef T type; };

template <typename Iter, typename F> void for_each_recursive(Iter begin, Iter end, F f);

template <typename F, bool Recurse> struct for_each_rec_impl;

template <typename F>
struct for_each_rec_impl<F, false>
{
  template <typename Iter>
  static typename std::enable_if<is_pair<typename std::iterator_traits<Iter>::value_type>::value, void>::type
  go(Iter begin, Iter end, F f)
  {
    for (Iter it = begin; it != end; ++it) f(it->second);
  }

  template <typename Iter>
  static typename std::enable_if<!is_pair<typename std::iterator_traits<Iter>::value_type>::value, void>::type
  go(Iter begin, Iter end, F f)
  {
    for (Iter it = begin; it != end; ++it) f(*it);
  }
};

template <typename F>
struct for_each_rec_impl<F, true>
{
  template <typename Iter>
  static typename std::enable_if<is_pair<typename std::iterator_traits<Iter>::value_type>::value, void>::type
  go(Iter begin, Iter end, F f)
  {
    for (Iter it = begin; it != end; ++it)
      {
        for_each_recursive(it->second.begin(), it->second.end(), f);
      }
  }

  template <typename Iter>
  static typename std::enable_if<!is_pair<typename std::iterator_traits<Iter>::value_type>::value, void>::type
  go(Iter begin, Iter end, F f)
  {
    for (Iter it = begin; it != end; ++it)
      {
        for_each_recursive(it->begin(), it->end(), f);
      }
  }
};

template <typename Iter, typename F>
void for_each_recursive(Iter begin, Iter end, F f)
{
  typedef typename std::iterator_traits<Iter>::value_type value_type;
  typedef typename final_value<value_type>::type type;

  for_each_rec_impl<F, is_container<type>::value>::go(begin, end, f);
}

Usage: for_each_recursive(v.begin(), v.end(), my_predicate<final_value_type>);


Barring a change of the data type, you're probably stuck with loops-within-loop.

However, I would start by re-writing the maps of maps of maps of .... vector into 1 map of vectors. I would recommend using either boost::tuple or std::tuple (C++0x) to create the class, but you can also define your own, and overload operator < so that it can be used as a map key (or write the comparator)

Using boost::tuple, if you have map<Key1, map< Key2, map<Key3, map<Key4, map<Key5, map<Key6, vector<T> > > > > > > you could rework it into map< boost::tuple< Key1, Key2, Key3, Key4, Key5, Key6 >, vector<T> >.


If you really must, you could do some template meta programming (for instance using boost mpl), to abstract away the loops. However, as many people have suggested, there is very likely a better solution to your original problem than one that needs 7 nested maps and a vector.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜