2010-12-15 8 views
1

Je suis très nouveau à F # ici, je rencontre le problème "Collection a été modifié" en F #. Je sais que ce problème est courant lorsque nous parcourons une collection en modifiant (en l'ajoutant/supprimant) en même temps. Et les threads précédents dans stackoverflow pointent également vers ceci.Aide avec F #: "Collection a été modifiée"

Mais dans mon cas, je travaille sur 2 jeux différents: J'ai 2 collections:

  • originalCollection la collection originale dont je veux supprimer des trucs
  • colToRemove une collection contenant les objets que je veux retirer

Ci-dessous le code:

Seq.iter (fun input -> ignore <| originalCollection.Remove(input)) colToRemove 

Et je suis arrivé l'erreur d'exécution suivante: + $ {exception System.InvalidOperationException: Collection a été modifiée; l'opération d'énumération peut ne pas s'exécuter. à System.ThrowHelper.ThrowInvalidOperationException (ressource de ExceptionResource) à System.Collections.Generic.List 1.Enumerator.MoveNextRare() at System.Collections.Generic.List 1.Enumerator.MoveNext() à [email protected] [T] (FSharpFunc 2 f, IEnumerator 1 e , FSharpRef 1 started, Unit unitVar0) at [email protected]ctions-IEnumerator-MoveNext() at Microsoft.FSharp.Collections.SeqModule.Iterate[T](FSharpFunc 2 l'action, la source IEnumerable`1)

est ici le morceau de code:

 match newCollection with 
     | Some(newCollection) -> 

      // compare newCollection to originalCollection. 
      // If there are things that exist in the originalCollection that are not in the newCollection, we want to remove them 
      let colToRemove = Seq.filter (fun input -> Seq.exists (fun i -> i.id = input.id) newCollection) originalCollection 
      Seq.iter (fun input -> ignore <| originalCollection.Remove(input)) colToRemove 

     | None ->() 

Merci!

Remarque: Si vous travaillez sur un environnement monothread ici, il n'y a pas de problèmes de multi-threading pouvant entraîner cette exception.

Répondre

5

Le problème ici est que colToRemove n'est pas une collection indépendante mais une projection de la collection originalCollection. Donc changer originalCollection change la projection qui n'est pas autorisée pendant l'itération. Le C# équivalent du code ci-dessus est le suivant

var colToRemove = originalCollection 
    .Where(input -> newCollection.Any(i -> i.id == input.id)); 
foreach (var in input in colToRemove) { 
    originalCollection.Remove(input); 
} 

Vous pouvez corriger ce problème en colToRemove une collection indépendante via la méthode List.ofSeq.

let colToRemove = 
    originalCollection 
    |> Seq.filter (fun input -> Seq.exists (fun i -> i.id = input.id) newCollection) originalCollection 
    |> List.ofSeq 
1

Je ne voudrais pas essayer de faire supprimer, puisque vous modifiez une collection, mais plutôt essayer de créer une autre collection comme ceci:

let foo() = 

    let orig = [1;2;3;4] 
    let torem = [1;2] 

    let find e = 
     List.tryFind (fun i-> i = e) torem 
     |> function 
     | Some _-> true 
     | None -> false 

    List.partition (fun e -> find e) orig 
    //or 
    List.filter (fun e-> find e) orig 

HTH

Questions connexes