开发者

Help with F#: "Collection was modified"

I am very new to F# here, I encounter the "Collection was modified" problem in F#. I know this problem is common when we are iterating through a Collection while modifying (adding/removing) it at the same time. And previous threads in stackoverflow also point to this.

But in my case, I am working on 2 different sets: I have 2 collections:

  • originalCollection the original collection from which I want to remove stuff
  • colToRemove a collection containing the objects that I want to remove

Below is the code:

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

And I got the following runtime error: + $exception {System.InvalidOperationException: Collection was modified; enumeration operation may not execute. at System.ThrowHelper.ThrowInvalidOperationException(ExceptionResource resource) at System.Collections.Generic.List1.Enumerator.MoveNextRare() at System.Collections.Generic.List1.Enumerator.MoveNext() at Microsoft.FSharp.Collections.IEnumerator.next@174[T](FSharpFunc2 f, IEnumerator1 e, FSharpRef1 started, Unit unitVar0) at Microsoft.FSharp.Collections.IEnumerator.filter@169.System-Collections-IEnumerator-MoveNext() at Microsoft.FSharp.Collections.SeqModule.Iterate[T](FSharpFunc2 action, IEnumerable`1 source)

here is the chunk of 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 -&g开发者_运维百科t; ignore <| originalCollection.Remove(input)) colToRemove

        | None -> ()

Thanks!

Note: Working on a single-threaded environment here, so there are no multi-threading issues that might result in this exception.


The problem here is that colToRemove is not an independent collection but is a projection of the collection originalCollection. So changing originalCollection changes the projection which is not allowed during the iteration. The C# equivalent of the above code is the following

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

You can fix this by making colToRemove an independent collection via the List.ofSeq method.

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


I would not try to do a remove, since you are modifying a collection, but instead try to create another collection like so:

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

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜