2011-09-13 22 views
8

Usando la biblioteca de impulso es posible comprimir juntos un número conocido de iteradores usando un zip iterator, pero ¿qué pasa cuando el número de iteradores que se deben comprimir no se conoce hasta el tiempo de ejecución?Zip Varios iteradores en C++

Para ampliar un poco, tengo una lista de listas que son todas del mismo tamaño, y tengo que agrupar todos los valores en cada índice y pasarlos a otra operación. En este momento, esto es todo manual, y creo que debería haber una mejor manera.

Ejemplo:

Decir que tengo 3 listas:

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

I necesidad de transformar estas listas en:

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

No sé cuántas listas hay en la entrada hasta el tiempo de ejecución.

+2

* * Creo que entiendo lo que quieres hacer, pero sería mejor si usted pone algo de código, describiendo lo que quiere hacer. ¡Tratar de resolver un problema * asumiendo * que lo entiendo, me pone nervioso en algún momento! – Nawaz

+3

@Nawaz: ¡Nos pone nerviosos también! –

+0

Esto se parece mucho a una _matriz de rotación_. No piense que hay adaptadores existentes para eso. – MSalters

Respuesta

4

Bien después de pasar casi 1/2 hora, se me ocurrió esta clase dynamic_zip_iterator que se puede mejorar aún más, para que se vea como un iterador similar a STL.A partir de ahora, es muy específica, como he hardcoded std::list en ella, que se puede sustituir con std::vector o puede hacer aún más genérica:

De todos modos, tener una mirada en ella:

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); 
    } 
}; 

Usándolo el problema se reduce a esta función: código

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;  
} 

prueba:

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; 
} 

Salida:

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

demostración en línea: http://ideone.com/3FJu1

2

Estoy bastante seguro de que ya no existe nada para eso. Pero ¿por qué no crear una lista muy simple de elementos de iterador? Eso haría el truco, estoy seguro!

crear una función para las 3 partes de la declaración for -> comenzar, terminar, incrementar

Y eso debería ser suficiente! Un poco más de detalle a continuación.

  • comienzan: (ref const a la lista de listas de referencia, a la lista vacía de iteradores) -> construir el iterador de la lista usando begin() para cada sublista

  • final: (ref const a la lista de iteradores, referencia const a la lista de listas) -> cierto si se iterador se encuentra al final de su lista de

  • de la subasta: (ref a la lista de iteradores) -> incremento cada iteración de la lista

+1

Esto debería funcionar siempre que todos los iteradores tengan el mismo tipo. Dado que 'zip_iterator' funciona con una tupla de iteradores, y él mismo se desreferencia a una tupla, el tipo de cada iterador y su reference_type pueden ser diferentes: esa información de tipo se enrolla en el tipo de zip_iterator. Un número determinado de iteradores determinado por el tiempo de ejecución obviamente no puede ser transferido al tipo de iterador, ni tampoco los diferentes tipos de referencia. Pero si son todos iguales y conocidos en tiempo de compilación, no hay problema. –

+0

@Steve Jessop: Entiendo su punto, pero dado que Chris menciona una lista de listas, no se puede argumentar que todos los iteradores tendrán el mismo tipo. –

Cuestiones relacionadas