0

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

谢谢!

4

1 回答 1

4

Func<T, T1...>您最有可能面临的问题是,当与 等相关时,F# 的类型推断很难用于 lambda Action<T>,尤其是在具有多个重载的方法中。

如果您使用的是为惯用的 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)
于 2012-12-02T08:10:18.710 回答