2 votes

Une alternative élégante au fait de boucler sur les mêmes données ?

J'ai un petit dilemme.

std::map<myClass, int>                  myMap;

void Distribute(){
    float pool = 50;
    int receivers = 0;
    for(auto i = myMap.begin(); i != myMap.end(); i++){
        if(i->second == 1) receivers++;
    }

    float distribution = pool/receivers;

    for(auto i = myMap.begin(); i!= myMap.end; i++){
        if(i->second == 0)continue;
        i->first.value = distribution;
    }
}

En gros, ce que j'essaie de faire, c'est de trouver la taille totale de la carte, moins les éléments dont les valeurs cartographiées sont égales à 0. Ensuite, je veux refaire une boucle sur la même carte, mais envoyer des valeurs à chaque entrée en utilisant les données que j'ai recueillies lors de la dernière boucle for.

Cela semble vraiment laid et inefficace. Il doit bien y avoir un moyen de gérer tout cela dans une seule boucle for ? Ou peut-être que la première boucle for ne serait idéalement pas nécessaire ? Je ne suis pas contre le travail supplémentaire, mais je ne peux pas m'empêcher de penser que j'écris du code moche ici, j'aimerais vraiment avoir un avis.

2voto

Ma Yue Points 69

Si vos données sont insérées par vous-même, vous pouvez utiliser une classe wrapper contenant votre carte

class Wrapper{
public:
  int receivers = 0;
  std::map<myClass, int> myMap;// be sure you have operator< for myClass
  void insert(pair<myClass, int> item){
    myMap.insert(item);
    // count receivers when you insert , get receivers in constant time
    if(item.second == 1){
      receivers++;
    }
  }
};

void Distribute(){
  float pool = 50;
  Wrapper wrapper;
//insert your items by wrapper.insert(..) , not wrapper.myMap.insert(..)
  float distribution = pool/wrapper.receivers;
  for(auto& [i, j]: wrapper.myMap){
    if(j == 1){
      i.value = distribution;// be sure value is a public member of myClass
    }
  }
}

0voto

Andrew Lazarus Points 4364

En supposant que tout est monofilaire.

Vous devez faire la boucle deux fois, mais vous pouvez stocker les adresses des éléments qui doivent être modifiés pour ne pas avoir à tester deux fois.

Notez qu'il y a un const_cast très laid dans ce code. Il est laid pour une raison. Vous ne voulez pas changer la clé d'une carte ; cela peut casser le comportement de la carte. Je pense que vous pouvez simplifier et améliorer votre conception en prenant le deuxième élément (l'indicateur 0 ou 1) et en le transformant en un élément de type champ dans maClasse. Alors vous n'avez pas besoin d'une carte, juste d'un ensemble, d'un vecteur ou d'une liste de myClass.

J'ai également dû définir un hachage et un opérateur== pour myClass. J'ai omis cette partie pour montrer la section importante.

void Distribute(){
    float pool = 50;
    std::vector<myClass*> nonzeros;
    for (auto iter = myMap.begin(); iter != myMap.end(); ++iter) {
        if (iter->second == 1) { nonzeros.push_back(const_cast<myClass *>(&(iter->first))); }
    }
    if (nonzeros.empty()) return;
    const float distribution = pool/nonzeros.size();
    std::for_each(nonzeros.begin(), nonzeros.end(),
        [distribution](decltype(nonzeros)::value_type pClass) {pClass->value = distribution;});
}

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X