具有重复元素的无限序列

时间:2012-01-18 23:22:09

标签: f#

我需要创建一个无限序列,其中包含无限重复的元素子序列。

[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 }

有没有标准的方式(功能)来做到这一点?

4 个答案:

答案 0 :(得分:18)

我认为您的方法在这种情况下很好。没有内置函数来实现重复,但如果您需要经常重复序列,您可以自己定义一个并在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) }

答案 1 :(得分:3)

我认为这不是一个成语,你所拥有的很好,但这里有一些选择。

如果将子序列更改为数组,则可以执行

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

但它并不短。

答案 2 :(得分:1)

这将作为一个(或多或少)单行程,而不必创建任何帮助对象。

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

答案 3 :(得分:1)

与Daniel的答案类似,但将其封装到一个函数中,并假装该函数在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)