Newsgroup: it.comp.lang.c++
Titolo: iteratori filtranti (tipo python generator)

Ho una struttura di dati un po' particolare, cioè non è fatta proprio a dovere. Per chi volesse entrare nel mondo del demonio, ovvero il mondo di ROOT, la classe è questa: 
http://root.cern.ch/root/html/TTree.html
. È un contenitore di oggetti eterogenei, per accedervi, per la mente contorta dei programmatori, bisogna fare una cosa del genere
TTree t (blablabla)
int uno, due;
fChain->SetBranchAddress("dato1", &uno);
fChain->SetBranchAddress("dato2", &due);
for (...)
{
  fChain->GetEntry(i)
  if (questiDatiMiPiacciono(uno,due))
    cout << uno << due;
}
questo approccio mi fa un po' ribrezzo. Il lavoro che devo fare è contare quante entries del mio TTree soddifano diversi criteri, e trovare il criterio ottimo. Ultimamente ho lavorato un po' in python e quindi ho pensato di implementare degli iteratori filtranti. Non ho la più pallida idea di come implementarli. Quello che vorrei fare è una cosa del genere:
from __future__ import generators
def pari(data):
    for n in data:
        if n%2==0:
            yield n
def tre(data):
    for n in data:
        if n%3==0:
            yield n
def main():
    lista = [4,5,6,7,9,10,11,18]
    print "multipli di 2:"
    for i in pari(lista):
        print i
    print "multipli di 3:"
    for i in tre(lista):
        print i
    print "multipli di 6:"
    for i in pari(tre(lista)):
        print i
if __name__ == "__main__":
    main()
ovviamente in c++. Le caratteristiche che ho bisogno sono: iteratori filtranti, e la possibilità di concatenare più iteratori (come ho fatto in 
    for i in pari(tre(lista)):
). Ovviamente in modo molto semplice.

 ). Ovviamente in modo molto semplice.
Direi che stai cercando remove_if.
http://www.cppreference.com/cppalgorithm/remove_if.html
Devi definire un oggetto funzionale (oppure una funzione, ma in tal caso non
puoi ovviamente definire uno stato interno) per ogni operazione, per
esempio:
class MultiploDiN
{
public:
        MultiploDiN( const int n ) : n(n) {}
        bool operator() (const int m) const { return (m%n == 0); }
private:
        const int n;
};
A questo punto lo puoi applicare a un qualsiasi contenitore STL (per esempio
vector) dandone gli estremi:
MultiploDiN m(5);
remove_if( v.begin(), v.end(), m );
Fai attenzione che remove_if, a dispetto del nome, non *rimuove* i dati, ma
li sposta in fondo al contenitore, e restituisce un iteratore all'ultimo
elemento che ha passato il filtro; quindi puoi definire, per esempio, una
funzione così:
#include <algorithm>
vector<int> filtraMultipli( vector<int> v, const int n )
{
        MultiploDiN m(5);
        v.erase( remove_if( v.begin(), v.end(), m ) );
        return v;
}
E avrai rimosso tutti i multipli di 5.
Ciao,
-Federico

Federico Zenith wrote:

ma nel tuo caso modifichi v, io in uscita vorrei solo un iteratore che salti gli elementi che non passano il test, non voglio modificare il contenitore.

 contenitore.
Be', fanne una copia. Almeno mi pareva di aver capito questo dal tuo codice
Python. pari(lista) e tre(lista) non restituiscono un vettore identico a
quello di ingresso? Credo di sì, altrimenti come fai a concatenarli?
Se vuoi un iteratore che salti certi elementi, potresti doverne creare uno
tu, cambiando per esempio l'operatore ++.
class mioIteratore : public vector<int>::iterator
{
public:
        operator++();
        operator++(int);
        // ... un sacco di altri
};
e aggiungere una condizione che se l'elemento successivo non soddisfa certe
proprietà, si passa a quello dopo ancora. Però mi sembra più lavoro del
necessario e non credo verrebbe fuori codice particolarmente leggibile.
Però non vedo proprio come puoi concatenare una cosa così. Non è che
questi «iteratori» sono terminologia Python, che non hanno molto a che fare
con gli iteratori del C++? Non è che pensi alle descrizioni di lista («list
comprehension»)?
Ciao,
-Federico

Federico Zenith wrote:

in realtà quelli che ho chiamati iteratori in python sono generatori e dovrebbero restituire iteratori.
Per esempio se faccio una ricerca in un database la cosa più intelligente credo sia farsi restituire un iteratore che itera sugli elementi della tabella che soddifano la query e non farsi restituire una sottotabella che contiene tutti i record che soddisfano la query.

 contiene tutti i record che soddisfano la query.
Allora, prova remove_copy_if.
http://www.cppreference.com/cppalgorithm/remove_copy_if.html
Ciao,
-Federico

 comprehension»)?
Nope. Le list comprehension esistono nativamente in Python, ma sono una
cosa diversa. 
Comunque a parte questo la tua soluzione riguardo all'iteratore che
"salta" elementi è la soluzione al problema specifico di OP, anche se
non ha la piena comodità dei generatori di Python.
-- 
-riko

 
http://www.cppreference.com/cppalgorithm/remove_copy_if.html
Gli iteratori da generatore python *non* fanno la copia. :P
-- 
-riko

 gli elementi che non passano il test, non voglio modificare il contenitore.
Non puoi derivare dalla classe iteratore, e nell'operatore incremento 
fare il test?
in pseudo codice che _assolutamente_ non compila:
do
{
 (iterator<blabla>::operator++)();
} while( MioTest(*this) || this == this->end() ) ;
return this;
-- 
Articolo 33 della Costituzione italiana: L'arte e la scienza sono 
libere e libero ne è l'insegnamento.
Se siete tosti: 
http://www.rexresearch.com/kervran/kervran.htm

 contenitore.
http://www.boost.org/doc/libs/1_36_0/libs/iterator/doc/filter_iterator.html
M