Como atualizar um elemento existente de std :: set?

Eu tenho um std::set , e gostaria de atualizar algum valor de um elemento existente nele. Observe que o valor que estou atualizando não altera a ordem no conjunto:

 #include  #include  #include  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 Set; void update(Set& s, Foo f) { std::pair 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; } 

Existe alguma maneira concisa de fazer isso? Ou eu tenho que verificar se o elemento já está lá e, em caso afirmativo, removê-lo, adicionar o valor e reinseri-lo?

Como val não está envolvido na comparação, ele pode ser declarado 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; } }; 

Isto implica que o valor de val pode mudar em logicamente-const Foo, o que significa que não deve afetar outros operadores de comparação, etc.

Ou você pode simplesmente remover e inserir, o que leva O (1) tempo adicional (comparado a acessar e modificar) se a inserção usar a posição imediatamente antes da anterior como a dica.

Algo como:

 bool alreadyThere = !p.second; // you forgot the ! if (alreadyThere) { Set::iterator hint = p.first; hint++; s.erase(p.first); s.insert(hint, f); } 

Não tente resolver este problema trabalhando em torno da constância de itens em um set . Em vez disso, por que não usar o map , que já expressa a relação de valor-chave que você está modelando e fornece maneiras fáceis de atualizar os elementos existentes.

Faça val mutable como:

 mutable int val; 

Agora você pode alterar / modificar / mudar val mesmo se foo é const:

 void f(const Foo & foo) { foo.val = 10; //ok foo.id = 11; //compilation error - id is not mutable. } 

A propósito, do seu código, você parece pensar que se p.second for true, o valor já existia no conjunto e, portanto, você atualiza o valor associado. Eu acho que você entendeu errado. É de fato outro caminho. O documento no cpluscplus diz:

O par :: segundo elemento no par é definido como verdadeiro se um novo elemento for inserido ou falso se um elemento com o mesmo valor existir.

o que é correto, na minha opinião.


No entanto, se você usar o std::map , sua solução será direta:

 void update(std::map & m, std::pair value) { m[value.first] += value.second; } 

O que faz este código? m[value.first] cria uma nova input se a chave não existir no mapa e o valor da nova input é o valor padrão de int que é zero. Por isso, adiciona value.second a zero . Ou então, se a chave existe, ela simplesmente adiciona value.second . Ou seja, o código acima é equivalente a isto:

 void update(std::map & m, std::pair value) { std::map::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 } } 

Mas isso é demais, não é? Seu desempenho não é bom. O anterior é mais conciso e muito performático.

você pode usar o MAP que tem access muito rápido ao seu elemento se você tiver CHAVE. Nesse caso, acho que usar o MAP seria a melhor maneira de alcançar a velocidade mais rápida. DST :: MAP

    Intereting Posts