2012-01-18 21 views
13

Ho bisogno di creare una sequenza infinita contenente una sottosequenza di elementi che si ripete all'infinito.Sequenza infinita con elementi ripetuti

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

Così ho scritto questo:

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

C'è un modo standard (funzione) per fare questo?

risposta

17

Penso che il tuo approccio sia buono in questo scenario. Non v'è alcuna funzione incorporata per implementare la ripetizione, ma se è necessario ripetere le sequenze spesso, è possibile definire uno voi stessi e renderlo disponibile nel modulo Seq:

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

Quindi è possibile ben scrivere Seq.repeat [ 1 .. 4 ], come se repeat era una funzione di libreria F # standard, perché F # IntelliSense mostra entrambe le funzioni dal modulo Seq e dal modulo Seq come se fossero state definite in un singolo modulo.

Oltre all'implementazione, è anche possibile utilizzare l'espressione di sequenza ricorsiva, che è un altro pattern abbastanza comune durante la generazione di sequenze. Utilizzando while è in qualche modo imperativi (anche se non hai bisogno di qualsiasi stato per semplici ripetizioni) rispetto alla ricorsione funzionale:

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

Questo approccio è migliore quando si vuole mantenere uno stato durante la generazione. Ad esempio, la generazione di tutti i numeri 1 .. utilizzando while non sarebbe così piacevole, perché sarebbe necessario lo stato mutabile. Utilizzando la ricorsione, è possibile scrivere la stessa cosa:

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

Non credo che ci sia un idioma per questo, e quello che hai va bene, ma qui ci sono alcune alternative.

Se si cambia subsequence a un array, si può fare

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

Utilizzando quello che hai, si potrebbe anche fare

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

ma non è più breve.

+4

Uno Gotcha qui: 'Seq.initInfinite' genera solo sequenze infinite per determinati valori di infinito. Da [documentazione] (http://msdn.microsoft.com/en-us/library/ee370429.aspx): "Iteration può continuare fino a Int32.MaxValue." –

+1

Si adatta alla definizione di infinito di Core lib, che è una definizione operativa utilizzabile. – Daniel

1

Questo lo farà come un (più o meno) one-liner, senza dover creare alcun oggetto ausiliario.

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

L'elenco [1; 2; 3; 4] era solo un esempio. In realtà ho una lista di oggetti di cui ho bisogno per costruire una sequenza. – Max

1

Simile alla risposta di Daniel, ma incapsula in una funzione, e facendo finta che la funzione è nel modulo 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) 
Problemi correlati