2010-12-15 84 views
1

我对F#非常新,在F#中遇到“收集已修改”问题。我知道这个问题在我们迭代集合的同时修改(添加/删除)它时很常见。并且在stackoverflow中的前面的线程也指向这一点。F#帮助:“收集已修改”

但在我而言,我的工作在2个不同的组: 我有2个类别:

  • originalCollection原来的集合。其中我想删除的东西
  • colToRemove集合包含我想要删除的物体

以下是代码:

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

而且我得到以下运行时错误: + $例外{System.InvalidOperationException:集合已修改;枚举操作可能不会执行。 在System.ThrowHelper.ThrowInvalidOperationException(ExceptionResource资源) 在System.Collections.Generic.List 1.Enumerator.MoveNextRare() at System.Collections.Generic.List 1.Enumerator.MoveNext() 在[email protected] [T](FSharpFunc 2 f, IEnumerator 1e中,FSharpRef 1 started, Unit unitVar0) at [email protected]ctions-IEnumerator-MoveNext() at Microsoft.FSharp.Collections.SeqModule.Iterate[T](FSharpFunc 2动作,IEnumerable`1源)

这里是代码块:

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

谢谢!

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

回答

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); 
} 

可以通过经由List.ofSeq方法制备colToRemove独立收集解决此问题。

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

心连心