2009-04-20 8 views
2

J'ai le code qui ressemble essentiellement comme ceci:Comment utiliser BOOST_FOREACH avec deux cartes std :: maps?

std::map<int, int> map1, map2; 
BOOST_FOREACH(int i, map1) 
{ 
    // do steps 1-5 here... 
} 
BOOST_FOREACH(int i, map2) 
{ 
    // do steps 1-5 (identical to above) here... 
} 

Est-il possible de concaténer les cartes pour éliminer le code en double dans la deuxième boucle? Ou un moyen d'étendre BOOST_FOREACH pour itérer sur deux cartes différentes en une fois? Évidemment, je ne veux pas augmenter la complexité temporelle du programme (sinon je pourrais juste créer une nouvelle carte et l'insérer dans map1 et map2). J'ai le sentiment qu'il me manque quelque chose de rudimentaire ici.

+0

était-ce intentionnellement que vous itérez over int? vous devez utiliser la paire non seulement int. ou a boost récemment gagné la possibilité d'itérer seulement sur la valeur? –

+0

Si quoi que ce soit, je m'attendrais à une telle fonctionnalité pour itérer seulement sur la clé ... mais cela ne fonctionne pas non plus sur ma version de Boost. – ephemient

Répondre

9

Vous pouvez définir une fonction:

typedef std::map<int, int> IntMap; 

void doStuffWithInt(IntMap::value_type &i) 
{ 
    // steps 1 to 5 
} 

BOOST_FOREACH(IntMap::value_type &i, map1) 
    doStuffWithInt(i); 
BOOST_FOREACH(IntMap::value_type &i, map2) 
    doStuffWithInt(i); 

Bien que dans ce cas, il pourrait être encore plus simple à utiliser std::for_each:

for_each(map1.begin(), map1.end(), doStuffWithInt); 
for_each(map2.begin(), map2.end(), doStuffWithInt); 
+0

Si vous mappez ints à ints (std :: map ), je crois que les itérateurs pointeront vers std :: pair et non plain plain? –

+0

ouais probablement, je n'avais pas vraiment remarqué cela - ne pas confondre le problème, il ne devrait pas être trop difficile à réparer –

+0

+1, parfois les solutions les plus simples sont les meilleurs :) –

2

En plus de la solution de 1800, que je recommande, il y a aussi diverses solutions hacky:

for (int stage = 0; stage < 2; stage++) { 
    BOOST_FOREACH(int i, stage == 0 ? map1 : map2) { 
     ... 
    } 
} 

typedef std::map<int, int> intmap; 
std::vector<intmap *> v; 
v.push_back(&map1); 
v.push_back(&map2); 
BOOST_FOREACH(intmap *m, v) { 
    BOOST_FOREACH(int i, *m) { 
     ... 
    } 
} 

Remarque: lorsque je vois des collègues écrire comme ça, parfois je suis submergé par une envie irrésistible d'aller les étrangler. À utiliser à vos risques et périls.

+0

+1 sur la note: Vous Il faut toujours considérer ce que vous obtenez et ce que vous perdez. Si vous gagnez seulement le compactage du code et que vous perdez la lisibilité, cela ne compense pas. –

+0

J'ai aussi voté pour, parce que j'aime vos deux façons de le faire. le premier est assez compact et lisible. le deuxième aussi.bien que je le change pour lire intmap * v [] = {& map1, & map2}; BOOST_FOREACH (intmap * m, v) {...}. Je pense que les tableaux "bruts" sont bien dans ce cas. –

3

L'idée ici est d'écrire un type spécial d'itérateurs pour fusionner virtuellement deux conteneurs, en ce qui concerne BOOST_FOREACH. Notez que je ne crée pas un nouveau conteneur parmi les deux existants. Je saute simplement de l'extrémité du premier conteneur() à l'itérateur begin() du second conteneur. Je n'ai pas essayé d'écrire la classe merged_iterator actuelle, mais même si cela peut prendre un peu de temps à écrire, ce n'est pas techniquement difficile. Je suis vraiment surpris de ne pas avoir trouvé quelque chose comme ça en utilisant google. Je n'ai pas cherché longtemps, cependant!

template<typename Container> 
boost::iterator_range< 
    merged_iterator<Container::iterator> 
    > 
concat_containers(Container& c1, Container& c2) 
{ 
    typedef merged_iterator<typename Container::iterator> MergedIterator; 
    typedef boost::iterator_range<MergedIterator> IteratorRange; 
    return IteratorRange(
    MergeIterator(c1.begin(), c1.end(), c2.begin(), c2.end()), 
    MergeIterator(c2.end(), c1.end(), c2.begin(), c2.end())); 
} 

// Now use a bit of magic to define merged_iterator<...> 
// And you'll be able to write 

BOOST_FOREACH(std::pair<int, int> i, concat_containers(map1, map2)) 
{ 
// Do whatever you want here 
} 
+0

Je l'ai implémenté il y a quelques jours pour une autre question. Notez qu'il n'est pas prouvé et pourrait nécessiter quelques ajustements: http://stackoverflow.com/questions/757153/concatenating-c-iterator-ranges-into-a-const-vector-member-variable-at-construc/757328# 757328 –

+0

+1 pour fournir une approche très générale qui pourrait être fait pour fonctionner même à travers différents types de conteneurs. Mais je pense que cela peut être sur-ingénierie pour le problème à portée de main - juste faire une fonction comme 0800 INFORMATIONS suggéré! :) –

+0

Juste c'est exagéré pour cette question particulière. Je pensais juste que je pourrais essayer et m'amuser :) –

0

Du haut de ma tête, je vais essayer

std::map<int, int> map1, map2; 
std::map<int, int>& maps = { map1, map2 } 
BOOST_FOREACH(std::map<int, int> map, maps) 
    BOOST_FOREACH(int i, map) 
    { 
     // do steps 1-5 here... 
    } 
0

Il est expliqué here.

Vous pouvez le faire:

std::map<int,int> m; 
typedef std::pair<int,int> pair_t; 
BOOST_FOREACH(pair_t p, m) 
1

Le plus simple est comme ceci:

std::map<int, int> map1, map2; 
int key, value; 
BOOST_FOREACH(boost::tie(key, value), boost::join(map1, map2)) 
{ 
    // do steps 1-5 here... 
} 

Et ne vous inquiétez pas les virgules ne confondez pas le préprocesseur à cause de la parenthèse.

Questions connexes