2012-01-18 13 views
13

Necesito crear una secuencia infinita que contenga una subsecuencia de elementos que se repita infinitamente.Secuencia infinita con elementos que se repiten

[1; 2; 3; 4; 1; 2; 3; 4; 1; 2; 3; 4; ...] 

Así que escribió esto:

let l = [1; 2; 3; 4] 
let s = seq { while true do yield! l } 

¿Hay una manera estándar (función) para hacer esto?

Respuesta

17

Creo que su enfoque es bueno en este escenario. No existe una función incorporada para poner en práctica la repetición, pero si es necesario repetir secuencias menudo, se pueden seleccionar uno mismo y hacer que esté disponible en el módulo Seq:

module Seq = 
    let repeat items = 
    seq { while true do yield! items } 

A continuación, puede muy bien escribir Seq.repeat [ 1 .. 4 ], como si repeat era una función de biblioteca F # estándar, porque F # IntelliSense muestra las dos funciones de su módulo Seq y del módulo Seq como si estuvieran definidas en un único módulo.

Además de su implementación, también puede usar la expresión de secuencia recursiva, que es otro patrón bastante común al generar secuencias. Usando while es en cierto modo imperativo (aunque no es necesario ningún estado de repeticiones simples) en comparación con la recursividad funcional:

let rec repeat items = 
    seq { yield! items 
     yield! repeat items } 

Este enfoque es mejor cuando se quiere mantener un cierto estado generando al mismo tiempo. Por ejemplo, generar todos los números 1 .. usando while no sería tan agradable, porque necesitaría un estado mutable. El uso de la recursividad, se puede escribir lo mismo que:

let rec numbersFrom n = 
    seq { yield n 
     yield! numbersFrom (n + 1) } 
3

No creo que haya una expresión idiomática para esto, y lo que tienes está bien, pero aquí hay algunas alternativas.

Si cambia de subsecuencia a una matriz, que puede hacer

let a = [|1; 2; 3; 4|] 
let s = Seq.initInfinite (fun i -> a.[i % a.Length]) 

El uso de lo que tiene, también se puede hacer

let l = [1; 2; 3; 4] 
let s = Seq.initInfinite (fun _ -> l) |> Seq.concat 

pero no es más corto.

+4

Una Gotcha aquí: 'Seq.initInfinite' solo genera secuencias infinitas para ciertos valores de infinito. De [documentación] (http://msdn.microsoft.com/en-us/library/ee370429.aspx): "La iteración puede continuar hasta Int32.MaxValue". –

+1

Se ajusta a la definición de infinito del Core lib, que es una definición de trabajo utilizable. – Daniel

1

Esto lo hará como (más o menos) una línea, sin tener que crear ningún objeto auxiliar.

let s = seq { while true do 
       for i in 1 .. 4 -> i } 
+0

La lista [1; 2; 3; 4] fue solo un ejemplo. En realidad tengo una lista de objetos de los que necesito construir una secuencia. – Max

1

Similar a la respuesta de Daniel, pero encapsula en una función, y pretender que la función se encuentra en el módulo Sec:

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) 
Cuestiones relacionadas