Как перебрать карту map of map of map of map of vector - PullRequest
0 голосов
/ 19 августа 2011

Я пытаюсь собрать все данные с карты, карты, карты, карты, карты, карты вектора без необходимости иметь 7 циклов в C ++.

Вот как выглядят данные:

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

Итак, я пытаюсь собрать все Элем 1, Элем 2 со всех карт на карту.

Может ли кто-нибудь помочь мне сделать это вместо очевидного цикла по каждой карте, который приведет к 7 циклам в C ++?

Спасибо за помощь.

Ответы [ 3 ]

4 голосов
/ 20 августа 2011

Мне нравится идея @ inflagranti - так что, без претензий на полезность, вот шаблон для каждого, который перебирает все.Он использует черту is_container из симпатичного принтера , которую я здесь не копирую.

Обновление: Теперь полностью отработано, чтобы иметь дело как с голымтипы значений и типы парных значений.

Обновление 2: Упрощен класс реализации благодаря @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);
}

Использование: for_each_recursive(v.begin(), v.end(), my_predicate<final_value_type>);

3 голосов
/ 20 августа 2011

Если исключить изменение типа данных, вы, вероятно, застряли в цикле внутри цикла.

Однако я бы начал с переписывания карт карт карт .... векторав 1 карту векторов.Я бы рекомендовал использовать boost :: tuple или std :: tuple (C ++ 0x) для создания класса, но вы также можете определить свой собственный и перегружать operator <, чтобы его можно было использовать в качестве ключа карты (илинапишите компаратор)

Используя boost :: tuple, если у вас есть map<Key1, map< Key2, map<Key3, map<Key4, map<Key5, map<Key6, vector<T> > > > > > >, вы можете преобразовать его в map< boost::tuple< Key1, Key2, Key3, Key4, Key5, Key6 >, vector<T> >.

2 голосов
/ 19 августа 2011

Если вам действительно нужно, вы можете сделать несколько шаблонов метапрограммирования (например, используя boost mpl), чтобы абстрагировать циклы.Однако, как полагают многие, вполне вероятно, что решение вашей исходной проблемы лучше, чем решение, которое требует 7 вложенных карт и вектора.

...