スポンサーサイト

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

F#によるLinq to Obj入門 (8) GroupJoin

まずはサンプル用のレコード型とシークエンスを定義しておきます。
 
type Emp =
    {ID : int;//ID番号
     name : string;//名前
     height : float;//身長
     sex :int //0が男,1が女
     }
     member this.disp () =
        printfn "%2d %s %3.1f %A" this.ID this.name this.height this.sex
 
let EmpSeq = seq[{ID = 1;name = "Jhon";height = 168.3;sex = 0};
                {ID = 3;name = "Jhon";height = 161.1;sex = 0};
                {ID = 8;name = "Kim";height = 168.3;sex = 1};
                {ID = 2;name = "Sawyer";height = 168.7;sex = 0};
                {ID = 13;name = "Michael";height = 155.0;sex = 0};
                {ID = 19;name = "Revecca";height = 154.8;sex = 1};
                {ID = 11;name = "Hugo";height = 176.6;sex = 0};
                {ID = 21;name = "Maggie";height = 149.1;sex = 1};
                {ID = 7;name = "Ben";height = 157.6;sex = 0}]
 
type Sex =
    { S_ID :int;
      expInJ : string
      expInE : string}
 
let SexSeq = seq[{S_ID = 0;expInJ = "男";expInE = "Man"};
                 {S_ID = 1;expInJ = "女";expInE = "Woman"}]  
                 
 
今回紹介するのはGroupJoinですが、これはいわばあるシークエンスをあるキーでグループ化したもの(こちらがJoinでいうところのインナー側です)と、別のシークエンスをJoinするという操作になります。
 
例 EmpSeqをsexでグループ化(インナー側)
    seq[(0,seq[{ID=1;...;sex=0};..;{ID=7;..;sex=0});
        (1,seq[ID=8;...;sex=1};...;[ID=21;..;sex=1])       ]
 
これと例えばS_IDをキーとしてSexSeq(アウター側)をJoin 
{S_ID = 0;expInJ = "男";expInE = "Man"}  ->結合<-(0,seq[{ID=1;...;sex=0};..;{ID=7;..;sex=0})
{S_ID = 1;expInJ = "女";expInE = "Woman"}->結合<-(1,seq[ID=8;...;sex=1};...;[ID=21;..;sex=1])
 
さらにここから、結果を作り出すという作業となります。
 
シンタックスとしては次のようになっています。
 
static member GroupJoin : 
        outer:IEnumerable<'TOuter> * 
        inner:IEnumerable<'TInner> * 
        outerKeySelector:Func<'TOuter, 'TKey> * 
        innerKeySelector:Func<'TInner, 'TKey> * 
        resultSelector:Func<'TOuter, IEnumerable<'TInner>, 'TResult> -> IEnumerable<'TResult> 
 
疑似的にF#のコードで書いてみると、例えば次の様になります。
 
> let myGourpJoin1 (outer:seq<_>) (inner:seq<_>) outerKeySelector innerKeySelector resultSelector =
    let groupedInner = Seq.groupBy (innerKeySelector) inner
    seq{for outerEle in outer do
            for (giKey,giSeq) in groupedInner do
                if giKey = (outerKeySelector outerEle) then
                    yield (resultSelector outerEle giSeq)};;
 
val myGourpJoin :
  seq<'a> -> seq<'b> -> ('a -> 'c) -> ('b -> 'c) -> ('a -> seq<'b> -> 'd) -> seq<'d> when 'c : equality
 
注意するのがresultSelectorが('a -> seq<'b> -> 'd)の形になることです。
 
使ってみます。
 
> myGroupJoin1 SexSeq EmpSeq 
              (fun oute -> oute.S_ID) (fun inn -> inn.sex) 
              (fun oute innSeq -> (oute.expInE, (Seq.map (fun p -> p.name) innSeq)));;
val it : seq<string * seq<string>> =
  seq
    [("Man", seq ["Jhon"; "Jhon"; "Sawyer"; "Michael"; ...]);
     ("Woman", seq ["Kim"; "Revecca"; "Maggie"])]1
     
自前のではなくちゃんと定義されている方を使ってみます。
 
> Enumerable.GroupJoin (SexSeq,EmpSeq, 
              (fun oute -> oute.S_ID), (fun inn -> inn.sex), 
              (fun oute innSeq -> (oute.expInE, (Seq.map (fun p -> p.name) innSeq))));;
 
val it : seq<string * seq<string>> =
  seq
    [("Man", seq ["Jhon"; "Jhon"; "Sawyer"; "Michael"; ...]);
     ("Woman", seq ["Kim"; "Revecca"; "Maggie"])]
 
Joinと同じで第一引数のインスタンスメソッドとしても定義されているので、次の様にもできます。
 
> SexSeq.GroupJoin(EmpSeq, 
                (fun oute -> oute.S_ID), (fun inn -> inn.sex), 
                (fun oute innSeq -> (oute.expInE, (Seq.map (fun p -> p.name) innSeq))));;
 
val it : seq<string * seq<string>> =
  seq
    [("Man", seq ["Jhon"; "Jhon"; "Sawyer"; "Michael"; ...]);
     ("Woman", seq ["Kim"; "Revecca"; "Maggie"])]
 
 
男女別の身長の平均を("Man",***)等の形で得るには次の様にします。
 
> Enumerable.GroupJoin (SexSeq,EmpSeq, 
              (fun oute -> oute.S_ID), (fun inn -> inn.sex), 
              (fun oute innSeq -> (oute.expInE, (innSeq |> Seq.map (fun p -> p.height) |> Seq.average))));;
 
val it : seq<string * float> = seq [("Man", 164.55); ("Woman", 157.4)]
スポンサーサイト

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

コメントの投稿

非公開コメント

プロフィール

T GYOUTEN

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

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

この人とブロともになる

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