帮助F#:“收集被修改”

时间:2010-12-15 19:56:58

标签: f#

我是F#的新手,我在F#中遇到了“Collection was modified”问题。我知道当我们在同时修改(添加/删除)它时迭代Collection时,这个问题很常见。 stackoverflow中的先前线程也指向此。

但就我而言,我正在开发两套不同的套装: 我有2个收藏:

  • originalCollection 我要删除内容的原始集合
  • colToRemove 包含我要删除的对象的集合

以下是代码:

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

我收到以下运行时错误: + $ exception {System.InvalidOperationException:Collection已被修改;枚举操作可能无法执行。    在System.ThrowHelper.ThrowInvalidOperationException(ExceptionResource资源)    在System.Collections.Generic.List 1.Enumerator.MoveNextRare() at System.Collections.Generic.List 1.Enumerator.MoveNext()    在Microsoft.FSharp.Collections.IEnumerator.next@174 [T](FSharpFunc 2 f, IEnumerator 1 e,FSharpRef 1 started, Unit unitVar0) at Microsoft.FSharp.Collections.IEnumerator.filter@169.System-Collections-IEnumerator-MoveNext() at Microsoft.FSharp.Collections.SeqModule.Iterate[T](FSharpFunc 2动作,IEnumerable`1 source)

这是代码块:

        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 -> ()

谢谢!

注意:在此处处理单线程环境,因此不存在可能导致此异常的多线程问题。

2 个答案:

答案 0 :(得分:5)

这里的问题是colToRemove不是一个独立的集合,而是集合originalCollection的投影。因此,更改originalCollection会更改迭代期间不允许的投影。上述代码的C#等价物如下

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

您可以通过colToRemove方法将List.ofSeq设为独立收藏来解决此问题。

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

答案 1 :(得分:1)

我不会尝试删除,因为您正在修改集合,而是尝试创建另一个集合,如下所示:

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