2011-01-09 10 views
3

nextLineを実装するのに一番の方法はありますか?Seqヘッドとテール

let s = ref seqOfLines 
let nextLine() = 
    let hd = Seq.head !s 
    s := Seq.skip 1 !s 
    hd 

seqOfLinesはこれを行うには

+3

's:= Seq.skip 1!s'のようなシーケンスの拡張を使うのは本当に悪い考えです。新しいシーケンスオブジェクトを他のものの上に作成するので、アルゴリズムはO(n^2) )。私が間違っているなら私を訂正してください。 –

+3

最初に 'nextLine'関数を使いたいのはなぜですか?あなたが持っているシーケンスを反復するだけでは、純粋な機能が得られません。 C#ではこの種のことさえできません。あなたがしていることを主張するなら、 's.GetEnumerator()'を適切に使い、 'nextLine'関数でそれを使うべきです。 –

+2

ここでソースコードを見ることができます:https://github.com/fsharp/fsharp/blob/master/src/fsharp/FSharp.Core/seq.fs#L1438新しいシーケンスを作成します。メモリの割り当てなどがあります。毎回1ステップずつ移動したいと思っているので、あなた自身がMoveNextを呼び出すことをお勧めします。 –

答えて

4

一つの方法は、基礎となるIEnumerator<String>を利用することで、無限であると仮定されます。それはかなりの1ライナーではありませんが、あなたが持っている実装より少しきれいに見えます。

本質的には、シーケンスからIEnumerator<'a>インターフェイスを取得してから、MoveNextを呼び出すだけでループします。これは、無限のシーケンスでうまく動作します。使用するには

> let getNextFunc (seqOfLines : seq<'a>) =    
-  let linesIE : IEnumerator<'a> = seqOfLines.GetEnumerator() 
-  (fun() -> ignore (linesIE.MoveNext()); linesIE.Current);; 

val getNextFunc : seq<'a> -> (unit -> 'a) 

は、ちょうどgetNextFuncシーケンスを渡すと、それはあなたのnextLine機能を返します。

> let sequenceOfStrings = seq { for i = 0 to 10000 do yield i.ToString() };; 

val sequenceOfStrings : seq<string> 

> let nextLine = getNextFunc sequenceOfStrings;; 

val nextLine : (unit -> string) 

> nextLine();; 
val it : string = "0" 
> nextLine();; 
val it : string = "1" 
> nextLine();; 
val it : string = "2" 
> nextLine();; 
val it : string = "3" 
2

うーん、私はあなたがあまりにも命令的にこれにアプローチしようとしている、その結果として、あなたには、いくつかのファンキーなコードを書くに終わるしようと関数型言語の利点を失っていると思います。

current stateが返され、value * next stateが返されるように関数を書き直すと便利です。これはあなたの機能を純粋に機能的に保ちます。また、あなたが直接、基本的な列挙子をタッチする必要はありませんので、それが簡単に、(あなたは、このためのF#のパワーパックを参照する必要が)代わりにLazyListにあなたの無限のseqを変換するために見つけるかもしれない:

> open LazyList 
let seqOfLines = Seq.initInfinite (fun i -> i) |> LazyList.ofSeq 
let nextLine = function Cons(x, xs) -> x, xs | Nil -> failwith "Empty list";; 

val seqOfLines : LazyList<int> 
val nextLine : LazyList<'a> -> 'a * LazyList<'a> 

> nextLine seqOfLines;; 
val it : int * LazyList<int> = (0, seq [1; 2; 3; 4; ...]) 
> nextLine (snd it);; 
val it : int * LazyList<int> = (1, seq [2; 3; 4; 5; ...]) 
> nextLine (snd it);; 
val it : int * LazyList<int> = (2, seq [3; 4; 5; 6; ...]) 
> nextLine (snd it);; 
val it : int * LazyList<int> = (3, seq [4; 5; 6; 7; ...]) 
0

FSharpx.Collectionsいくつかを持っていますSeq.tail、Seq.Head、Seq.UnConsなどの便利で効率的な関数です。Seqを頭や尾に分解したい場合に便利です。