Помощь с F #: «Коллекция была изменена» - PullRequest
1 голос
/ 15 декабря 2010

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

Но в моем случае я работаю над 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 () в 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 action, 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 ]

5 голосов
/ 15 декабря 2010

Проблема здесь в том, что 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 голос
/ 16 декабря 2010

Я бы не пытался сделать удаление, поскольку вы изменяете коллекцию, но вместо этого попробуйте создать другую коллекцию, например, так:

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...