Eu estava tentando apagar uma série de elementos do mapa com base em uma condição particular. Como faço isso usando algoritmos STL?
Inicialmente pensei em usar, remove_if
mas não é possível, pois remove_if não funciona para container associativo.
Existe algum algoritmo equivalente "remove_if" que funciona para o mapa?
Como uma opção simples, pensei em percorrer o mapa e apagar. Mas repetir o mapa e apagar é uma opção segura? (Já que os iteradores ficam inválidos após o apagamento)
Usei o seguinte exemplo:
bool predicate(const std::pair<int,std::string>& x)
{
return x.first > 2;
}
int main(void)
{
std::map<int, std::string> aMap;
aMap[2] = "two";
aMap[3] = "three";
aMap[4] = "four";
aMap[5] = "five";
aMap[6] = "six";
// does not work, an error
// std::remove_if(aMap.begin(), aMap.end(), predicate);
std::map<int, std::string>::iterator iter = aMap.begin();
std::map<int, std::string>::iterator endIter = aMap.end();
for(; iter != endIter; ++iter)
{
if(Some Condition)
{
// is it safe ?
aMap.erase(iter++);
}
}
return 0;
}
for(auto iter=aMap.begin(); iter!=aMap.end(); ){ ....}
para reduzir a desordem. O descanso é como os outros disseram. Esta pergunta me poupou um pouco de confusão agora ;-)Respostas:
Quase.
O que você tinha originalmente incrementaria o iterador duas vezes se você apagasse um elemento dele; você poderia potencialmente pular elementos que precisavam ser apagados.
Este é um algoritmo comum que vi usado e documentado em muitos lugares.
[EDIT] Você está correto ao dizer que os iteradores são invalidados após um apagamento, mas apenas os iteradores que fazem referência ao elemento que foi apagado, outros iteradores ainda são válidos. Portanto, usando
iter++
naerase()
chamada.fonte
map
, retornam o próximo iterador deerase(iter)
. É muito mais limpo de fazeriter = erase( iter )
.erase_if para std :: map (e outros contêineres)
Eu uso o seguinte modelo para isso.
Isso não retornará nada, mas removerá os itens do std :: map.
Exemplo de uso:
Segundo exemplo (permite que você passe em um valor de teste):
fonte
std
. Eu entendo por que não é membro destd::map
, mas acho que algo parecido deveria estar na biblioteca padrão.std::map
e outros.Agora,
std::experimental::erase_if
está disponível no cabeçalho<experimental/map>
.Veja: http://en.cppreference.com/w/cpp/experimental/map/erase_if
fonte
Eu obtive esta documentação da excelente referência SGI STL :
Portanto, o iterador que você possui que está apontando para o elemento a ser apagado, obviamente, será invalidado. Faça algo assim:
fonte
erase
ser chamado. Portanto, eles são de fato equivalentes. Ainda assim, eu prefiro fortemente sua versão em vez da original.O código original tem apenas um problema:
Aqui, o
iter
é incrementado uma vez no loop for e outra vez no erase, o que provavelmente terminará em algum loop infinito.fonte
Aqui está uma solução elegante.
fonte
Das notas de fundo de:
http://www.sgi.com/tech/stl/PairAssociativeContainer.html
um Container Associativo de Par não pode fornecer iteradores mutáveis (conforme definido nos requisitos do Trivial Iterator), porque o tipo de valor de um iterador mutável deve ser Atribuível e o par não é Atribuível. No entanto, um Container Associativo de Par pode fornecer iteradores que não são completamente constantes: iteradores de forma que a expressão (* i) .second = d seja válida.
fonte
Primeiro
Em segundo lugar, o código a seguir é bom
Ao chamar uma função, os parâmetros são avaliados antes da chamada dessa função.
Portanto, quando o iter ++ é avaliado antes da chamada para apagar, o operador ++ do iterador retornará o item atual e apontará para o próximo item após a chamada.
fonte
IMHO não há
remove_if()
equivalente.Você não pode reordenar um mapa.
Portanto,
remove_if()
não pode colocar seus pares de interesse no final em que você pode ligarerase()
.fonte
Baseado na resposta do Iron Savior Para aqueles que gostariam de fornecer uma gama mais próxima das linhas de iteradores de tomadas funcionais padrão.
Curioso para saber se há alguma maneira de perder os
ContainerT
itens e obtê-los do iterador.fonte
A resposta de Steve Folly Eu me sinto mais eficiente.
Aqui está outra solução fácil, mas menos eficiente :
A solução usa
remove_copy_if
para copiar os valores que queremos em um novo contêiner e, em seguida, trocar o conteúdo do contêiner original pelo novo:fonte
Se você quiser apagar todos os elementos com chave maior que 2, a melhor maneira é
Porém, funciona apenas para intervalos, não para qualquer predicado.
fonte
Eu uso assim
fonte