2010-12-15 4 views
1

Я очень новичок в F # здесь, я столкнулся с проблемой «Коллекция была изменена» в F #. Я знаю, что эта проблема распространена, когда мы выполняем итерацию через Collection при одновременном изменении (добавлении/удалении). И предыдущие потоки в stackoverflow также указывают на это.Помощь с F #: «Коллекция была изменена»

Но в моем случае, я работаю на 2-х различных наборов: У меня есть 2 коллекции:

  • originalCollection оригинальную коллекцию, с которой я хочу, чтобы удалить StuFF
  • 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 1 е , 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); 
} 

Вы можете это исправить, сделав colToRemove независимой коллекции с помощью метода List.ofSeq.

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 

НТН