Como remover objetos de uma coleção IEnumerable em um loop [duplicado]
-
03-07-2019 - |
Pergunta
Esta questão já tem uma resposta aqui:
Duplicar
Modificando uma coleção durante a iteração Through It
Alguém tem um teste padrão agradável para me permitir contornar a incapacidade de remover objetos enquanto eu loop através de uma coleção enumerável (por exemplo, um IList ou KeyValuePairs em um dicionário)
Por exemplo, o seguinte falhar, uma vez que modifica a Lista sendo enumerado mais durante o foreach
foreach (MyObject myObject in MyListOfMyObjects)
{
if (condition) MyListOfMyObjects.Remove(myObject);
}
No passado, eu usei dois métodos.
Eu ter substituído o foreach com um revertida para loop (de modo a não alterar as quaisquer índices estou looping sobre se eu remover um objeto).
I também têm tentado armazenar uma nova colecção de objectos para remover dentro de loop, em seguida ciclo através de que a recolha e removidos os objectos a partir da colecção original é.
Estes funcionam bem, mas nem sente bom, e eu queria saber se alguém surgiu com a mais elegante solução para a questão
Solução
Há um método List<T>.RemoveAll(Predicate<T> match)
útil que eu acho que é projetado para este: http: / /msdn.microsoft.com/en-us/library/wdka673a.aspx
Outras dicas
É meio simplória, mas quando eu pretendo itens apagar de um IEnumerable / IList Eu normalmente apenas fazer uma cópia:
foreach (MyObject myObject in new List<MyObject>(MyListOfMyObjects))
{
if (condition) MyListOfMyObjects.Remove(myObject);
}
Não é a forma mais eficiente de fazê-lo, mas é fácil de ler. otimização prematura e tudo isso.
Faça o inverso, criando uma nova lista:
List myFilteredList = new List();
foreach (MyObject myObject in myListOfMyObjects)
{
if (!condition) myFilteredList.Add(myObject);
}
Em seguida, use a nova lista sempre que você precisar.
Você também pode usar uma expressão LINQ facilmente, novamente, invertendo a condição. Isto tem a vantagem de não criar uma nova estrutura, mas também as armadilhas de ser um enumeráveis ??preguiçoso:
var myFilteredList = from myObject in myListOfMyObjects
where !condition
select myObject;
No entanto, se você realmente precisa para remover os itens da lista, eu normalmente usam o "criar uma nova lista, em seguida, reiterar e remover" abordagem.
Eu deparei com este post e pensei que iria partilhar.
void RemoveAll(object condition)
{
bool found = false;
foreach(object thisObject in objects)
{
if (condition)
{
objects.Remove(thisObject);
found = true;
break; //exit loop
}
}
// Call again recursively
if (found) RemoveAll(condition);
}
Eu não gosto da ideia revertida para loop, uma vez que só funciona em determinadas estruturas de dados.
Em I geral usaria a segunda técnica e acumular os itens a serem eliminados em uma recolha selectiva 'a-ser-excluídos'. Se eliminação pode causar itera existente para ser invalidado (como vai acontecer com qualquer coleção árvore equilibrada, por exemplo), então eu não vejo uma maneira de contornar isso.
A única outra técnica que eu usei ocasionalmente é reiniciar toda a iteração quando você encontrar o primeiro elemento a ser excluído. Se você fazê-lo através sem encontrar nenhum produto para excluir, em seguida, a função está acabado. Isto é ineficiente, mas às vezes neccessary se excluir um item da coleção pode alterar o conjunto de itens que precisam ser excluídos.
Eu tenho um dicionário e quer se desfazer de todos os valores. Quando cada valor é descartado ele remove-se do dicionário que cria o problema de discutir. Eu fiz o seguinte:
foreach (var o in dictionary.Values.ToList())
{
o.Dispose();
}
Eu aprecio isso pode estar morto agora, mas do jeito que eu sempre faço é:
foreach (MyObject myObject em MyListOfMyObjects)
{
if (condição) MyListOfMyObjects.Remove (myObject);
break;
}
O objeto é removido e, em seguida, sai do loop, viola!