C++ 我想在遍历std::map时对其执行就地修改

C++ 我想在遍历std::map时对其执行就地修改,c++,C++,我需要知道对地图进行就地修改的最佳方法,而无需获取修改值的本地副本,然后将其再次推入原始地图 我已经详细介绍了下面解释问题的片段: #include <string> #include <map> struct EmployeeKey { std::string name; int amount; int age; }; struct EmployeeDetail { std::string dept; int section;

我需要知道对地图进行就地修改的最佳方法,而无需获取修改值的本地副本,然后将其再次推入原始地图

我已经详细介绍了下面解释问题的片段:

#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;
}  
#包括
#包括
结构EmployeeKey
{
std::字符串名;
整数金额;
智力年龄;
};
结构雇员详情
{
字符串部门;
int段;
国际工资;
};
bool comparebyname(const std::string和name,
康斯特国际酒店,
施工人员(钥匙和钥匙)
{
返回name>key.name&&age>key.age;
}
typedef std::map EmployeeMap;
int main()
{
EmployeeMap-eMap;
//在地图中插入条目
年龄=10岁;
std::string name=“John”;
员工地图;
国际热核实验堆(iter,eMap)
{
if(compareByNameAge(名称、年龄、iter->first))
{
//**这就是我想要避免的。。。。。。。
//复制修改后的数据
//把它推到新地图上。
员工详细数据=iter->秒;
det.salary=1000;
transformMap[iter->first]=det;
}
}
//**还有,我也需要避免。。。
//对修改后的值执行cpy
//从变换贴图到
//原始地图
foreach(iter1、transformMap)
eMap[iter1->first]=iter1->second;
}  

只需引用该值即可

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

获取对EmployeeDetail的引用。

iter->second
是对
EmployeeDetail
对象的引用,您可以直接修改它-例如

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

无需使用
transformMap

您只需通过迭代器直接修改元素(迭代器直接指向相应的项):

对于更复杂的修改,可以通过引用获取值:

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

<>在C++中,通常可以在迭代时不修改集合,但这仅意味着不能删除/添加项。在C++11中,修改现有项通常是可以的。您不能修改的是
映射中的键和
集合中元素的任何部分,但这些都是c++11中的
常量,因此您不能修改它们。在C++03中,您需要记住不要更改
集合中元素的键部分

不仅仅是迭代映射并执行

iter->second.salary=1000


解决您的问题?

foreach
迭代期间,可以更改
映射
对象的值(
值类型
第二部分)。您无法添加或删除任何键—无
insert
erase

你就不能这样做吗

it->second.salary = 1000;

如果您有C++11,请尝试以下方法:

for (auto& pair : eMap )
  if (pair.first.name == "Rob")
    pair.second.salary *= 1000;
for(EmployeeMap::iterator it = eMap.begin(); it != eMap.end(); ++it)
  if(pair.first.name == "Rob")
    pair.second.hours /= 2;
注意:您只能更改
第二对
<代码>配对。第一个
是常量,不能更改(毕竟,它是映射的键。)

如果您没有C++11,请尝试以下方法:

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

不能使用
std::transform
,因为它分配迭代器,并且映射迭代器的
第一个
元素始终是常量

此外,您的代码没有显示员工密钥的比较,因此我假设您有一个实现严格弱排序的密钥。基本纲要:

但是,您可以对每个_使用
,因为谓词可以是无状态的:

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

C++17使用结构化绑定进行更新:

for (auto &[key, detail] : employeeMap)
    if (compareByNameAge(name, age, key))  
        detail.salary = 1000;   

添加引用。员工详情&det=iter->secondl;将更改映射中的副本。@SidharthShekahr:因此,对
循环使用普通的
(基于范围,如果您的编译器支持),或对每个
使用
std::for,或对每个
使用
BOOST\u FOREACH
;或者修复自定义的
foreach
以提供非常量迭代器。什么是
foreach
?我很确定这不是C++关键字。@ SID:注意,转换也会重复,所以迭代是不被避免的,但是在其他地方移动。<代码> const Type(CONT)和UnQuyNoNeX(YC)= cont < /C>。这是你的问题。您正在遍历对容器的常量引用。如果您拥有
foreach
宏,只需修复它即可。否则。。。做点别的。你有C++11吗?我无法获得EmployeeDetail的引用,因为我们的每个版本都支持常量迭代器。@Sid:只需自己编写循环,代码就少得多,更易于阅读和维护,而且运行时和内存效率比您多次复制的想法要高得多。您能建议一种方法来使用std::transform执行boost::bind,这样我就可以避免这个迭代,让transform来执行这些操作。@Sid,您并不是真的在避免迭代,它只是被一些奇特的语法隐藏了,为什么不保持原样呢?在c++11中,对于(auto-It:eMap){…}{/code>@Sid,发生的事情非常可读(除了自定义的
foreach
),这变得更加简单
:您不能直接将
transform
bind
一起使用,因为您不是在转换容器,而是只修改一些值,这意味着您仍然需要
if
或一个函子,最终代码的复杂性将大于普通迭代,使代码不易维护,当然,除非您编写一个小lambda,在这种情况下,它也同样可维护,但是
transform
方法会稍微低效一些,因为它会重写所有元素,即使是未修改的元素。