Zip Несколько итераторов в C ++ - PullRequest
8 голосов
/ 13 сентября 2011

Используя библиотеку boost, можно сжать известное количество итераторов с помощью zip iterator , но как насчет того, когда число итераторов, подлежащих сжатию, неизвестно до времени выполнения?

Чтобы немного расширить, у меня есть список списков одинакового размера, и мне нужно сгруппировать все значения каждого индекса и передать их в другую операцию.Прямо сейчас это все руководство, и я чувствую, что должен быть лучший способ.

Пример :

Скажем, у меня есть 3 списка:

  • [1, 2, 3, 4, 5]
  • [11, 12, 13, 14, 15]
  • [21, 22, 23, 24, 25]

Мне нужно преобразовать эти списки в:

  • [1, 11, 12]
  • [2, 12, 22]
  • [3, 13, 23]
  • [4, 14, 24]
  • ... и т. Д.

Я не знаю, сколько списков на входедо времени выполнения.

Ответы [ 2 ]

4 голосов
/ 13 сентября 2011

Хорошо, потратив почти полчаса, я придумал этот класс dynamic_zip_iterator, который можно еще улучшить, чтобы он выглядел как STL-подобные итераторы. На данный момент это очень специфично, так как я жестко закодировал std::list в нем, который вы можете заменить на std::vector или сделать еще более универсальным:

В любом случае, посмотрите на это:

template<typename T>
struct dynamic_zip_iterator
{
   typedef typename std::list<T>::iterator list_iterator;
   std::list<list_iterator> iterators;
   std::list<std::list<T>> * plists;
   dynamic_zip_iterator(std::list<std::list<T>> & lists, bool isbegin) : plists(&lists) 
   {
         auto it = plists->begin();
         for( ; it != plists->end(); ++it)
         {
           if ( isbegin )
                iterators.push_back(it->begin()); 
           else
                iterators.push_back(it->end()); 
         }
   }
   dynamic_zip_iterator(const dynamic_zip_iterator & zip) : 
          plists(zip.plists),iterators(zip.iterators) {}

   dynamic_zip_iterator operator++()
   { 
     auto it = iterators.begin();
     for( ; it != iterators.end(); ++it)
          ++(*it);
     return *this;
   }
   std::list<T> operator*() 
   { 
     std::list<T> lst;
     auto it = iterators.begin();
     for( ; it != iterators.end(); ++it)
          lst.push_back(*(*it));     
     return lst;
   }
   bool operator!=(dynamic_zip_iterator &zip)
   { 
     auto it1 = iterators.begin();
     auto it2 = zip.iterators.begin();
     return (*it1) != (*it2);
   }
   static dynamic_zip_iterator begin(std::list<std::list<T>> & lists)
   {
      return dynamic_zip_iterator<T>(lists, true);
   }
   static dynamic_zip_iterator end(std::list<std::list<T>> & lists)
   {
      return dynamic_zip_iterator<T>(lists, false);
   }
};

Используя его, ваша проблема сводится к этой функции:

std::list<std::list<int>> create_lists(std::list<std::list<int>>& lists)
{
  std::list<std::list<int>> results;
  auto begin = dynamic_zip_iterator<int>::begin(lists);
  auto end = dynamic_zip_iterator<int>::end(lists);
  for( ; begin != end ; ++begin)
  {
     results.push_back(*begin);
  }
  return results;    
}

Тестовый код:

int main() {
        int a[] = {1, 2, 3, 4, 5}, b[] = {11, 12, 13, 14, 15}, c[] = {21, 22, 23, 24, 25};
        std::list<int> l1(a,a+5), l2(b,b+5), l3(c,c+5);
        std::list<std::list<int>> lists;
        lists.push_back(l1); 
        lists.push_back(l2);
        lists.push_back(l3);
        std::list<std::list<int>> newlists = create_lists(lists);
        for(auto lst = newlists.begin(); lst != newlists.end(); ++lst)
        {
                std::cout << "[";
                std::copy(lst->begin(), lst->end(), std::ostream_iterator<int>(std::cout, " "));
                std::cout << "]" << std::endl;
        }
        return 0;
}

Выход:

[1 11 21 ]
[2 12 22 ]
[3 13 23 ]
[4 14 24 ]
[5 15 25 ]

Онлайн демо: http://ideone.com/3FJu1

2 голосов
/ 13 сентября 2011

Я почти уверен, что сегодня для этого ничего не существует. Но почему бы не создать очень простой список элементов итератора? Это бы сработало, я уверен!

Создать функцию для всех 3 частей оператора for -> начало, конец, приращение

И этого должно быть достаточно! Чуть подробнее ниже.

  • begin: (const ref для списка списков, ссылка на пустой список итераторов) -> создать список итераторов, используя begin () для каждого подсписка

  • end: (const ref для списка итераторов, const ref для списка списков) -> true, если один итератор находится в конце своего списка

  • приращение: (ссылка на список итераторов) -> приращение каждого итератора в списке

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...