F#中Observable.GroupBy的示例用法

时间:2012-12-02 01:18:42

标签: f# system.reactive

我正在尝试确定如何在Reactive Extensions中使用group by功能。有人有一个简单的例子来说明它在F#中使用吗?

谢谢!

1 个答案:

答案 0 :(得分:4)

你最有可能面临的问题是,当与Func<T, T1...>Action<T>等相关时,F#的类型推断对于lambdas来说很难,特别是在具有多次重载的方法中。

如果您正在使用专为C#/ VB设计的Rx API,那么大多数时候您最终都必须注释类型以指向编译器正确的方向。

GroupBy以其最简单的形式接受一个键选择器并产生一个可观察的组。每个组都有一个键,它本身就是一个Observable,它是该键下的值流。

在这个例子中,我们形成了两个组:偶数或奇数,因此你得到两个IGroupedObservable<string, int>SelectMany用于重新组合这些组。

使用常规Rx方法:

let log message s = printfn "%s: %A" message s       

let disposable = 
    Observable.Interval(TimeSpan.FromSeconds(0.5))
              .Select(int)              
              .Do(log "Produced")
              .GroupBy(fun n -> if n % 2 = 0 then "Even" else "Odd")
              .SelectMany(fun (group : IGroupedObservable<string, int>) -> group.Select(fun i -> group.Key, i))          
              .Do(log "Kind")
              .Subscribe()              

这是非常可怕的......

为了使它更具惯用性,你需要像这样扩充Observable模块:

type Observable with
    static member log message o = Observable.Do(o, log message)
    static member groupBy selector o = Observable.GroupBy(o, (fun v -> selector(v)))
    static member collect (selector : 'a -> IObservable<'b>) o = Observable.SelectMany(o, selector)

现在您可以在上面表达相同的代码:

let disposable = 
    Observable.Interval(TimeSpan.FromSeconds(0.5))
    |> Observable.map int
    |> Observable.log "Produced"
    |> Observable.groupBy (fun n -> if n % 2 = 0 then "Even" else "Odd")
    |> Observable.collect(fun group -> group |> Observable.map(fun i -> group.Key, i))                  
    |> Observable.log "Kind"
    |> Observable.subscribe(fun _ -> ())

...更具可读性,无需注释。

输出:

Produced: 0
Kind: ("Even", 0)
Produced: 1
Kind: ("Odd", 1)
Produced: 2
Kind: ("Even", 2)
Produced: 3
Kind: ("Odd", 3)