2015-05-09 5 views
0

Я хотел бы группа очень большая последовательность лениво используя код вроде следующего:Есть ли ленивая версия функции Fq's Seq.groupBy?

// native F# version 
let groups = 
    Seq.initInfinite id 
     |> Seq.groupBy (fun i -> i % 10) 
for (i, group) in groups |> Seq.take 5 do 
    printfn "%A: %A" i (group |> Seq.take 5) 

Ожидаемый результат:

1: seq [1; 11; 21; 31; ...] 
2: seq [2; 12; 22; 32; ...] 
3: seq [3; 13; 23; 33; ...] 
4: seq [4; 14; 24; 34; ...] 
5: seq [5; 15; 25; 35; ...] 

Однако на практике эта программа петель бесконечно, печать ничего. Можно ли это сделать в F #?

Я готов использовать Linq вместо встроенных функций, но и GroupBy и ToLookup производят такое же поведение (даже если GroupBy Linq, как предполагается, быть ленивым):

// Linq version 
let groups = 
    Enumerable.GroupBy(
     Seq.initInfinite id, 
     (fun i -> i % 10)) 
for group in groups |> Seq.take 5 do 
    printfn "%A" (group |> Seq.take 5) 

Возможно, я делаю что-то непреднамеренно, что вызывает нетерпеливую оценку?

+0

Нет, это не вы, это реализация методов. Они не совсем ленивы - они не начнут оценивать, если вам не нужны результаты, но все результаты будут сгенерированы сразу же, что происходит. Но это потому, что такой сценарий, как ваш, необычен. – MarcinJuraszek

+0

ОК, ну, это неутешительно. Благодарю. – brianberns

ответ

2

Есть две вещи, чтобы сказать:

Прежде всего, как вы знаете, сколько групп будет в бесконечной последовательности? С другими словами, сколько предметов вам нужно материализовать, чтобы получить ваши 5 групп сверху? Сколько вам нужно будет материализовать, если вы попросите 11 групп? Понятно, что даже нелегко объяснить неформально, что должно произойти, когда вы лениво группируетесь.

Во-вторых, группа Rx группы является ленивой и, вероятно, как можно ближе к тому, что вы хотите: http://rxwiki.wikidot.com/101samples#toc24 Эта версия группы работает, потому что она реагирует на каждый элемент и запускает соответствующую группу как таковую, вы получаете событие, когда новый элемент потребляется, и вы получаете информацию о том, в какой группе это произошло, а не о получении списка групп.

+0

Зачем мне нужно знать, сколько групп будет «впереди», так как сами группы возвращаются в ленивой последовательности? Если 5-я группа не генерируется до триллионного элемента в последовательности, то, очевидно, «взять 5» групп будет очень дорого. Тем не менее, «взять n» на уровне группы должно вернуть первые N групп, сгенерированных последовательностью, так же, как «взять n» на уровне элемента возвращает первые N элементов, сгенерированных последовательностью. Каким образом последовательности на групповом уровне отличаются от последовательностей на уровне элементов? – brianberns

+0

(Кроме того, фактически, я действительно точно знаю, сколько групп будет в этом случае, поскольку функция группировки является оператором мод. Но даже в этом случае функция groupBy слишком нетерпелива, потому что мне не удается передать эта информация во время разговора. Может быть, есть разумное решение проблемы с учетом конечного, полностью заданного набора групп вверх? Подпись будет чем-то вроде «groupByLazy fixedArrayOfGroups groupingFunction inputSequence».) – brianberns

+0

Ну, это проблема: скажите, что вы перечисляете вторая группа. Чтобы перейти к первому элементу этой группы, вам нужно перечислить некоторое количество элементов, не так ли? Теперь, что бы вы сделали с ними? Cache? Игнорируй их? –

1

Моя Hopac библиотеки для F # имеет осуществление так называемой choice streams (presentation), которые являются ленивыми и одновременно/асинхронным, а также обеспечить groupBy операции.

+0

Спасибо, я проверю это. – brianberns