2012-02-08 3 views
4

変更した値のローカルコピーを取らずにもう一度押す必要はありません。元の地図にstd :: mapの位置を変更しながら繰り返して実行したい

#include <string> 
#include <map> 
struct EmployeeKey 
{ 
    std::string name; 
    int amount; 
    int age; 
}; 

struct EmployeeDetail 
{ 
    std::string dept; 
    int section; 
    int salary; 
}; 

bool compareByNameAge(const std::string& name, 
         const int& age, 
         const EmployeeKey& key) 
{ 
    return name > key.name && age > key.age; 
} 

typedef std::map<EmployeeKey, EmployeeDetail> EmployeeMap; 

int main() 
{ 
    EmployeeMap eMap; 
    // insert entries to the map 
    int age = 10; 
    std::string name = "John"; 

    EmployeeMap transformMap; 
    foreach(iter, eMap) 
    { 
     if (compareByNameAge(name, age, iter->first)) 
     { 
      //**This is what i want to avoid....... 
      // take a copy of the data modified 
      // push it in a new map. 
      EmployeeDetail det = iter->second; 
      det.salary = 1000; 
      transformMap[iter->first] = det; 
     } 
    } 

    //** Also, i need to avoid too... 
    // do the cpy of the modified values 
    // from the transform map to the 
    // original map 
    foreach(iter1, transformMap) 
     eMap[iter1->first] = iter1->second; 
} 
+1

は、参照を追加します。述語はステートレスすることができるので

あなたは、しかしfor_eachを使用することができます。 EmployeeDetail&det = iter-> secondl;マップ内のコピーが変更されます。 – Dan

+0

あなたのような単純な変更を行うには、 'iter-> second.salary = 1000;'のように適切に動作するはずです。キーを変更したり、コレクションからアイテムを挿入/削除したりすることはできません。 –

+0

これは動作しません。 for_eachバージョンはconst_iteratorsのみをサポートしています。 – Sid

答えて

3

ちょうど値への参照を取る:私はそれ以下のスニペットを詳しく説明している

は、問題を説明しています。

EmployeeDetail& det = iter->second; // notice new '&' character. 
det.salary = 1000; // modifies the 'EmployeeDetail' object in-place. 
0

EmployeeDetailへの参照を取得します。

+0

私たちがサポートしているfor_eachバージョンとしてEmployeeDetailの参照を取得できません。 – Sid

+0

@Sid:自分でループを書くだけで、はるかにコードが少なく、読みやすく保守がはるかに簡単で、ランタイムとメモリは、何度も何度も物をコピーする考えよりも効率的です。 – PlasmaHH

3

iter->secondは、EmployeeDetailオブジェクトへの参照です。このオブジェクトは直接変更できます。あなたが取ることができ、より複雑な変更のための

foreach(iter, eMap) 
{ 
    if (compareByNameAge(name, age, iter->first)) 
    iter->second.salary = 1000; 
} 

を:あなたは、単に(対応するアイテムを直接指す)イテレータから直接要素をmodifiyでき

foreach(iter, eMap) 
    { 
     if (compareByNameAge(name, age, iter->first)) 
     { 
      iter->second.salary = 1000; 
     } 
    } 

transformMap

+0

あなたは、boost :: bindをstd :: transformとする方法を提案して、この繰り返しを避けて、変換するようにすることができますか? – Sid

+2

@Sid、あなたは反復を本当に避けているわけではありません。構文として、それをそのまま残してみませんか? – Nim

+0

@Sid: 'transform'を使うことはできません(これは、あなたのカスタム' foreach'を除いて)非常に読みやすくなっています。コンテナを変換するのではなく、むしろ値のうちのいくつかしか変更しないので、 'if'やファンクタが必要になり、最後に複雑さが増すので、' bind'を直接行います小さなラムダを書くのでなければコードを保守しにくくしてしまいます。その場合、それは保守性が高くなりますが、 'transform'アプローチはやや効率が悪くなります変更されていない要素も含め、すべての要素を書き換えます。 –

5

は必要ありません参照による値:

EmployeeDetail& det = iter->second; 
det.salary = 1000; 

C++では、通常は反復処理中はコレクションを変更しませんが、それはアイテムを削除/追加できないことを意味します。 C++ 11では、既存の項目を変更するのが一般的です。変更できないものは、mapのキーと、setの要素のいずれかの部分ですが、いずれにしても、C++ 11ではconstとなり、変更することはできません。 C++ 03では、setの要素のキー・パーツを変更しないことを覚えておく必要があります。

1

はちょうどマップを反復処理し、

iter-> second.salary = 1000をしていないでしょう。

あなたの問題を解決しますか?

1

それはforeach反復中mapオブジェクト(value_typesecond一部)の値を変更するために罰金です。キーを追加または削除することはできません。insertまたはeraseはありません。

1

あなたは次の操作を行うことはできませんか?

it->second.salary = 1000; 
0

あなたがC++ 11を持っている場合は、これを試してみてください。

for (auto& pair : eMap) 
    if (pair.first.name == "Rob") 
    pair.second.salary *= 1000; 

注意:あなたが唯一のpair.secondを変更することができます。 pair.firstは(それは、結局、マップのキーである。)のconstで、変更してはならない

あなたがC++ 11を持っていない場合は、これを試してみてください。

for(EmployeeMap::iterator it = eMap.begin(); it != eMap.end(); ++it) 
    if(pair.first.name == "Rob") 
    pair.second.hours /= 2; 
1

することができますイテレータを割り当てるためにstd::transformを使用し、マップイテレータのfirst要素は常にconstです。

さらに、コードでは従業員のキーの比較は表示されないため、厳密な弱い発注を実装していると仮定します。基本的なアウトライン:

class SalaryUpdater 
{ 
public: 
    SalaryUpdater(const std::string& name, int age) : name_(name), age_(age) { } 

    void operator()(EmployeeMap::value_type& item) 
    { 
     if(compareByNameAge(name_, age_, item.first)) 
     { 
      item.second.salary = 1000; 
     } 
    } 

private: 
    std::string name_; 
    int age_; 
}; 

int main() 
{ 
    EmployeeMap eMap; 
    // insert entries to the map 

    std::for_each(eMap.begin(), eMap.end(), SalaryUpdater("John", 10)); 
} 
関連する問題