スポンサーサイト

上記の広告は1ヶ月以上更新のないブログに表示されています。
新しい記事を書く事で広告が消せます。

F#によるLinq to Obj入門 (11) SequenceEqual

今回はSequenceEaualです。
 
seq{...}は遅延評価ですので、必要になるまで、要素の生成がなされません。
例えば
 
> seq{yield 1} = seq{yield 1};;
val it : bool = false
 
の結果からもわかるように、等式に出てきただけでは、その時点での評価はなされません。
要素の生成がなされたかどうかわかるように、printf文を入れてみます。
 
> seq{printf "created 1"; yield 1} = seq{printf "created 2";yield 1};;
val it : bool = false
 
ちゃんと評価して要素が同じかどうかをたしかめるにはSequenceEqualを利用します。
 
> Enumerable.SequenceEqual(seq{printf "created 1"; yield 1},seq{printf "created 2";yield 1});;
created 1created 2val it : bool = true
 
いつもと同様に次の様にも書けます。
 
(seq{printf "created 1"; yield 1}).SequenceEqual(seq{printf "created 2";yield 1})
 
(注意)
> seq[1;1;2] = seq[1;1;2];;
val it : bool = true
 
から類推されるように、list、arrayから生成する場合は通常の=が使用できるようですが、SequenceEqualを使った方が安全かと思われます。
 
(注意)LINQの拡張メソッドも遅延評価なものが多数含まれるので注意が必要です。
(最後に一覧をつける予定です。)
 
自前でSequenceEqualを定義してみます。
 
> let mySequenceEaual (seq1:seq<'a>) (seq2:seq<'a>) =
    use e1 = seq1.GetEnumerator()
    use e2 = seq2.GetEnumerator()
    let rec loop (st1,st2) =
        if st1 = false && st2 = false then true
        elif
            st1 <> st2 then false
        else // st1 = true && st2 ture
            if e1.Current <> e2.Current then false
            else
               loop ((e1.MoveNext()), (e2.MoveNext()))       
    loop ((e1.MoveNext()), (e2.MoveNext())) ;;
 
val mySequenceEaual : seq<'a> -> seq<'a> -> bool when 'a : equality
 
> mySequenceEaual (seq[]) (seq[]);;
val it : bool = true
 
> mySequenceEaual (seq[1]) (seq[]);;
val it : bool = false
 
> mySequenceEaual (seq[1]) (seq[1]);;
val it : bool = true
 
> mySequenceEaual (seq[1;2]) (seq[1]);;
val it : bool = false
 
> mySequenceEaual (seq[1;2;3]) (seq{for i in [1 .. 3] -> i});;
val it : bool = true
 
さて次はSeqモジュールの方ですがこちらにはcompareWithが定義されています。
 
Seq.compareWith : ('T -> 'T -> int) -> seq<'T> -> seq<'T> -> int
 
というシグネチャーで、第一引数で比較関数をわたします。
 
比較関数は
型: 'T -> 'T -> int
であり
各シーケンスの要素を受け取り、int を返す関数です。
 
comparWithは要素ごとに 2 つのシーケンスを比較て比較関数の最初のゼロ以外の結果を返します。シーケンスの末尾に達すると、最初のシーケンスの方が短い場合は -1、2 番目のシーケンスが短い場合は 1 を返します。
 
例(下の例では0が出れば、二つのシークエンスは等しい)
 
let f x y = x - y と定義しておいて
 
> Seq.compareWith f (seq[1;2;3]) (seq{for i in [1 .. 3] -> i});;
val it : int = 0
 
> Seq.compareWith f (seq[1;2;3]) (seq{for i in [1 .. 2] -> i});;
val it : int = 1
 
> Seq.compareWith f (seq[1;5]) (seq{for i in [1 .. 2] -> i});;
val it : int = 3

なお、比較可能な型を使う場合はcompareという関数が定義されているのでこれを使うとよいです。
 
> compare ;;
val it : ('a -> 'a -> int) when 'a : comparison = <fun:it@1>
 
> Seq.compareWith compare (seq[1;5]) (seq {1..2});;
val it : int = 1
スポンサーサイト

テーマ : プログラミング
ジャンル : コンピュータ

コメントの投稿

非公開コメント

余計なお世話

seq { for i in [1..3] -> i }
seq { for i in 1..3 -> i }
seq { 1..3 }
同じ意味

あとこういう典型的な比較関数には
別途定義しなくても
compare が使えます。
Seq.compareWith compare (seq[1;5]) (seq {1..2})

No title

コメントありがとうございます。本文へ取り入れさせていただきました。
プロフィール

T GYOUTEN

Author:T GYOUTEN
F#と英単語とフリーソフトと読書に興味があります。
ホームページでフリーソフトも公開しています。どぞ御贔屓に。

最新記事
最新コメント
最新トラックバック
月別アーカイブ
カテゴリ
フリーエリア
フリーエリア
blogram投票ボタン
検索フォーム
RSSリンクの表示
リンク
ブロとも申請フォーム

この人とブロともになる

QRコード
QRコード
上記広告は1ヶ月以上更新のないブログに表示されています。新しい記事を書くことで広告を消せます。