C++ 如何更新 std::set 的现有元素?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/7340434/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to update an existing element of std::set?
提问by Frank
I have a std::set<Foo>, and I'd like to update some value of
an existing element therein. Note that the value I'm updating does not change the order in the set:
我有一个std::set<Foo>, 我想更新其中现有元素的一些值。请注意,我正在更新的值不会更改集合中的顺序:
#include <iostream>
#include <set>
#include <utility>
struct Foo {
Foo(int i, int j) : id(i), val(j) {}
int id;
int val;
bool operator<(const Foo& other) const {
return id < other.id;
}
};
typedef std::set<Foo> Set;
void update(Set& s, Foo f) {
std::pair<Set::iterator, bool> p = s.insert(f);
bool alreadyThere = p.second;
if (alreadyThere)
p.first->val += f.val; // error: assignment of data-member
// ‘Foo::val' in read-only structure
}
int main(int argc, char** argv){
Set s;
update(s, Foo(1, 10));
update(s, Foo(1, 5));
// Now there should be one Foo object with val==15 in the set.
return 0;
}
Is there any concise way to do this? Or do I have to check if the element is already there, and if so, remove it, add the value and re-insert?
有什么简洁的方法可以做到这一点吗?或者我是否必须检查该元素是否已经存在,如果是,将其删除,添加值并重新插入?
回答by Cubbi
Since valis not involved in comparison, it could be declared mutable
由于val不涉及比较,因此可以声明mutable
struct Foo {
Foo(int i, int j) : id(i), val(j) {}
int id;
mutable int val;
bool operator<(const Foo& other) const {
return id < other.id;
}
};
This implies that the value of valmay change in a logically-const Foo, which means that it shouldn't affect other comparison operators etc.
这意味着 的值val可能会在逻辑常量 Foo 中发生变化,这意味着它不应该影响其他比较运算符等。
Or you could just remove and insert, that takes O(1) additional time (compared to accessing and modifying) if insertion uses the position just beforejust after the old one as the hint.
或者,您可以删除和插入,如果插入使用旧位置之前的位置作为提示,则需要 O(1) 额外的时间(与访问和修改相比)。
Something like:
就像是:
bool alreadyThere = !p.second; // you forgot the !
if (alreadyThere)
{
Set::iterator hint = p.first;
hint++;
s.erase(p.first);
s.insert(hint, f);
}
回答by Mark B
Don't try to solve this problem by working around the const-ness of items in a set. Instead, why not use map, which already expresses the key-value relationship you are modeling and provides easy ways to update existing elements.
不要试图通过解决set. 相反,为什么不使用map,它已经表达了您正在建模的键值关系,并提供了更新现有元素的简单方法。
回答by Nawaz
Make valmutable as:
使val可变为:
mutable int val;
Now you can change/modify/mutate valeven if foois const:
现在,val即使foo是 const,您也可以更改/修改/变异:
void f(const Foo & foo)
{
foo.val = 10; //ok
foo.id = 11; //compilation error - id is not mutable.
}
By the way, from your code, you seem to think that if p.secondis true, then the value already existed in the set, and therefore you update the associated value. I think, you got it wrong. It is in fact other way round. The docat cpluscplus says,
顺便说一句,从您的代码中,您似乎认为如果p.second为真,则该值已存在于集合中,因此您更新了关联的值。我想,你弄错了。它实际上是相反的。cpluscplus的文档说,
The pair::second element in the pair is set to true if a new element was inserted or false if an element with the same value existed.
如果插入了新元素,则pair::second 元素设置为true,如果存在具有相同值的元素,则设置为false。
which is correct, in my opinion.
这是正确的,在我看来。
However, if you use std::map, your solution would be straightforward:
但是,如果您使用std::map,您的解决方案将很简单:
void update(std::map<int,int> & m, std::pair<int,int> value)
{
m[value.first] += value.second;
}
What does this code do? m[value.first]creates a new entry if the key doesn't exist in the map, and value of the new entry is default value of intwhich is zero. So it adds value.secondto zero. Or else if the key exists, then it simply adds value.secondto it. That is, the above code is equivalent to this:
这段代码有什么作用?m[value.first]如果映射中不存在键,则创建一个新条目,并且新条目的值为默认值int为零。所以它添加value.second到zero. 否则,如果键存在,那么它只是添加value.second到它。也就是说,上面的代码等价于这个:
void update(std::map<int,int> & m, std::pair<int,int> value)
{
std::map<int,int>::iterator it = m.find(value);
if ( it != m.end()) //found or not?
it.second += value; //add if found
else
{
m.insert(value); //insert if not found
}
}
But this is too much, isn't it? It's performance is not good. The earlier one is more concise and very performant.
但这太多了,不是吗?它的性能并不好。前一个更简洁,性能也非常好。
回答by sam
you can use MAP witch has very fast access to your element if you have KEY . in this case i think using MAP would be better way to achieve fastest speed . STD::MAP
如果您有 KEY ,您可以使用 MAP 女巫可以非常快速地访问您的元素。在这种情况下,我认为使用 MAP 是实现最快速度的更好方法。性病::地图

