2010-12-15 80 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 

心連心