Я пытаюсь взять большой файл и разделить его на несколько небольших файлов. Место, где происходит каждый разнесение, основано на предикате, возвращенном после изучения содержимого каждой данной строки (функция isNextObject
).Создание последовательности последовательностей вызывает StackOverflowException
Я попытался прочитать в большом файле через функцию File.ReadLines
, чтобы я мог выполнять итерацию по файлу по одной строке за один раз без необходимости хранить весь файл в памяти. Мой подход состоял в том, чтобы сгруппировать последовательность в последовательность меньших подпоследовательностей (по одному на файл, который должен быть выписан).
Я нашел полезную функцию, которую создал Томас Петричек на fssnip под названием groupWhen. Эта функция отлично поработала для моего первоначального тестирования на небольшом подмножестве файла, но при использовании реального файла возникает исключение StackoverflowException. Я не уверен, как настроить группу. Чтобы предотвратить эту функцию (я все еще являюсь зеленым цветом F #).
Вот упрощенная версия кода, показывая только соответствующие части, которые воссоздают StackoverflowExcpetion ::
// This is the function created by Tomas Petricek where the StackoverflowExcpetion is occuring
module Seq =
/// Iterates over elements of the input sequence and groups adjacent elements.
/// A new group is started when the specified predicate holds about the element
/// of the sequence (and at the beginning of the iteration).
///
/// For example:
/// Seq.groupWhen isOdd [3;3;2;4;1;2] = seq [[3]; [3; 2; 4]; [1; 2]]
let groupWhen f (input:seq<_>) = seq {
use en = input.GetEnumerator()
let running = ref true
// Generate a group starting with the current element. Stops generating
// when it founds element such that 'f en.Current' is 'true'
let rec group() =
[ yield en.Current
if en.MoveNext() then
if not (f en.Current) then yield! group() // *** Exception occurs here ***
else running := false ]
if en.MoveNext() then
// While there are still elements, start a new group
while running.Value do
yield group() |> Seq.ofList }
Это суть кода делает функцию использования Tomas':
module Extractor =
open System
open System.IO
open Microsoft.FSharp.Reflection
// ... elided a few functions include "isNextObject" which is
// a string -> bool (examines the line and returns true
// if the string meets the criteria to that we are at the
// start of the next inner file)
let writeFile outputDir file =
// ... write out "file" to the file system
// NOTE: file is a seq<string>
let writeFiles outputDir (files : seq<seq<_>>) =
files
|> Seq.iter (fun file -> writeFile outputDir file)
И вот соответствующий код в консольном приложении, который использует следующие функции:
let lines = inputFile |> File.ReadLines
writeFiles outputDir (lines |> Seq.groupWhen isNextObject)
Любые идеи о правильном способе остановки группы. Когда вы дуете стек? Я не уверен, как бы преобразовать функцию для использования аккумулятора (или вместо этого использовать продолжение, которое, я думаю, является правильной терминологией).
я сделал что-то похожее на это для реализации Hadoop/MR в F # - https: // GitHub. com/isaacabraham/HadoopFs/blob/master/HadoopFs/Core.fs # L9-L24 –
Выглядит интересно @IsaacAbraham благодарит. Я должен проверить проект, чтобы показать себя еще более реальным F #. –