Бесконечная последовательность с повторяющимися элементами
Мне нужно создать бесконечную последовательность, содержащую подпоследовательность элементов, которая бесконечно повторяется.
[1; 2; 3; 4; 1; 2; 3; 4; 1; 2; 3; 4; ...]
Итак, я написал это:
let l = [1; 2; 3; 4]
let s = seq { while true do yield! l }
Существует ли стандартный способ (функция)?
Ответы
Ответ 1
Я думаю, что ваш подход хорош в этом сценарии. Для реализации повторения нет встроенной функции, но если вам нужно часто повторять последовательности, вы можете определить ее самостоятельно и сделать ее доступной в модуле Seq
:
module Seq =
let repeat items =
seq { while true do yield! items }
Затем вы можете красиво написать Seq.repeat [ 1 .. 4 ]
, как если бы repeat
была стандартной библиотечной функцией F #, потому что F # IntelliSense показывает обе функции из вашего модуля Seq
и модуля Seq
, как если бы они были определены в единый модуль.
Помимо вашей реализации, вы также можете использовать выражение рекурсивной последовательности, которое является еще одним довольно распространенным шаблоном при генерации последовательностей. Использование while
в некотором роде является императивным (хотя вам не нужно какое-либо состояние для простых повторений) по сравнению с функциональной рекурсией:
let rec repeat items =
seq { yield! items
yield! repeat items }
Этот подход лучше, если вы хотите сохранить некоторое состояние при генерации. Например, генерация всех чисел 1 ..
с помощью while
будет не такой приятной, потому что вам нужно изменить состояние. Используя рекурсию, вы можете написать то же самое, что:
let rec numbersFrom n =
seq { yield n
yield! numbersFrom (n + 1) }
Ответ 2
Я не думаю, что для этого есть идиома, и то, что у вас есть, хорошо, но вот несколько альтернатив.
Если вы измените свою подпоследовательность на массив, вы можете сделать
let a = [|1; 2; 3; 4|]
let s = Seq.initInfinite (fun i -> a.[i % a.Length])
Используя то, что у вас есть, вы также можете сделать
let l = [1; 2; 3; 4]
let s = Seq.initInfinite (fun _ -> l) |> Seq.concat
но это не короче.
Ответ 3
Это сделает его как однострочный (более или менее), без необходимости создавать какие-либо вспомогательные объекты.
let s = seq { while true do
for i in 1 .. 4 -> i }
Ответ 4
Как и Дэниел, ответьте, но инкапсулируя его в функцию и притворившись, что функция находится в модуле Seq:
module Seq =
let infiniteOf repeatedList =
Seq.initInfinite (fun _ -> repeatedList)
|> Seq.concat
// Tests
let intList = [1; 2; 3; 4]
let charList = ['a'; 'b'; 'c'; 'd']
let objList = [(new System.Object()); (new System.Object()); (new System.Object()); (new System.Object())]
do
Seq.infiniteOf intList |> Seq.take 20 |> Seq.iter (fun item -> printfn "%A" item)
Seq.infiniteOf charList |> Seq.take 20 |> Seq.iter (fun item -> printfn "%A" item)
Seq.infiniteOf objList |> Seq.take 20 |> Seq.iter (fun item -> printfn "%A" item)