2012-02-08 7 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

참조를 추가합니다. 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

우리는 const_iterators를 지원하는 for_each 버전으로 EmployeeDetail 참조를 가져올 수 없습니다. – Sid

+0

@ 시드 (Sid) : 반복문을 여러 번 복사하는 것보다 루프를 직접 작성하여 코드가 훨씬 적어 읽고 읽고 유지하기가 쉬우 며 런타임 및 메모리가 훨씬 효율적입니다. – PlasmaHH

3

iter->secondEmployeeDetail 개체에 대한 참조입니다.이 개체는 직접 수정할 수 있습니다. 예 :

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

당신은 단순히 (해당 항목에 직접 점) 직접 반복자를 통해 요소 modifiy 수 transformMap

+0

당신은 std :: transform으로 boost :: bind를 할 수있는 방법을 제안 할 수 있습니다. 그래서이 반복을 피하고 변형 시키십시오. – Sid

+2

@ 시드, 당신은 반복을 피하지 못합니다. 구문, 왜 그대로 두지 않습니까? 그것은 C++ 11에서 (사용자 정의'foreach'를 제외하고) 일어나는 일을 매우 읽기 쉽습니다. 이것은 (자동 it : eMap) {...}' – Nim

+0

@Sid :'transform'을 사용할 수 없습니다. 당신이 * 컨테이너를 변형하지 않고 * 값의 일부만을 수정하기 때문에'bind '가 직접적으로 필요합니다. 이는'if' 나 functor가 여전히 필요하다는 것을 의미합니다. 물론 작은 람다 (lambda)를 쓰지 않는 한 코드를 유지하기가 쉽지 않은 평범한 반복보다 더 큽니다.이 경우 유지할 수 있지만 변환 방법은 약간 비효율적입니다. 수정되지 않은 모든 요소를 ​​다시 씁니다. –

5

에 대한 필요가 없습니다 : 당신이 걸릴 수 있습니다 더 복잡한 수정에 대한

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

을 참조에 의한 가치 :

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

C++에서 당신은 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입니다.

또한 코드에 직원 키 비교가 표시되지 않으므로 약한 주문이 구현 된 것으로 가정합니다. 기본 개요 : 술어가 상태가 될 수 있기 때문에

당신은,하지만 for_each를 사용할 수 있습니다

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)); 
} 
관련 문제