Pergunta

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

Foi útil?

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!

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top