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.List
1.Enumerator.MoveNext()
at Microsoft.FSharp.Collections.IEnumerator.next@174[T](FSharpFunc2 f, IEnumerator
1 e, FSharpRef1 started, Unit unitVar0)
at Microsoft.FSharp.Collections.IEnumerator.filter@169.System-Collections-IEnumerator-MoveNext()
at Microsoft.FSharp.Collections.SeqModule.Iterate[T](FSharpFunc
2 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
精彩评论