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
方法会稍微低效一些,因为它会重写所有元素,即使是未修改的元素。