优雅的替代方法可以遍历相同的数据?

时间:2019-02-06 01:36:14

标签: c++

有点困境。

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

基本上,我想做的是找到地图的总大小,减去映射值为0的元素。此后,我想再次遍历同一张地图,但是使用我从上一个for循环中收集的数据。

这确实很丑陋且效率低下。当然,必须有某种方法可以将所有这些都以1为循环进行处理吗?也许理想情况下不需要第一个for循环?我不反对多余的工作,但是我不禁感到自己在这里写丑陋的代码,我真的很想输入一些信息。

2 个答案:

答案 0 :(得分:2)

如果您自己插入了数据,则可以使用包含地图的包装器类

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

答案 1 :(得分:0)

假设所有内容都是单线程的。

您必须执行两次循环,但是您可以存储需要更改的元素的地址,因此不必进行两次测试。

请注意,此代码中有一个非常丑陋的const_cast。这是一个丑陋的原因。您不想更改地图的键;它会破坏地图的行为。我怀疑您可以通过采用第二个元素(0或1指示符)并将其设为myClass中的 field 来简化和改进您的设计。这样,您就不需要地图,只需一个myClass的集合,向量或列表即可。

我还必须为myClass定义哈希和operator ==。我省略了该部分以显示重要部分。

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