C# 是否有可能在按键分组的热可观察项目中对最新项目进行采样?

C# 是否有可能在按键分组的热可观察项目中对最新项目进行采样?,c#,.net,reactive-programming,system.reactive,rx.net,C#,.net,Reactive Programming,System.reactive,Rx.net,在Rx.NET中,是否可以在按键分组的热观测中对最新项目进行采样 例如,如果我有一个IObservable,其中Price是: Price - Key - Bid - Offer 让我们假设IObservable链接到外部价格提要 我是否能够检索到所有最新的价格,按键分组,使用Rx每1秒采样一次?假设有一些可观察的源,这将返回在最后一秒中按键分组和采样的所有价格 var sampled = source .GroupBy(p => p.Key) .SelectMany(

在Rx.NET中,是否可以在按键分组的热观测中对最新项目进行采样

例如,如果我有一个
IObservable
,其中
Price
是:

Price 
- Key
- Bid
- Offer
让我们假设
IObservable
链接到外部价格提要


我是否能够检索到所有最新的
价格
,按
键分组,使用Rx每1秒采样一次?

假设有一些可观察的
,这将返回在最后一秒中按键分组和采样的所有价格

var sampled = source
    .GroupBy(p => p.Key)
    .SelectMany(o => o.Sample(TimeSpan.FromSeconds(1)));
如果某个价格在最后一秒钟内没有收到消息,则不包括在内

如果您希望包含旧价格,这将起作用:

var sampled2 = source
    .Scan(ImmutableDictionary<int, Price>.Empty, (state, p) => state.SetItem(p.Key, p))
    .Replay(1)
    .RefCount();
var dummySubscription = sampled2.Subscribe();
var result = Observable.Interval(TimeSpan.FromSeconds(1))
    .SelectMany(_ => sampled2.Take(1).SelectMany(state => state.Values));
var sampled2=源
.Scan(ImmutableDictionary.Empty,(state,p)=>state.SetItem(p.Key,p))
.重播(1)
.RefCount();
var dummySubscription=sampled2.Subscribe();
var结果=可观察的时间间隔(时间跨度从秒(1))
.SelectMany(=>sampled2.Take(1).SelectMany(state=>state.Values));

只需确保在处理
结果
可观察时处理
DummySubscription

假设某个可观察的
,这将返回在最后一秒按键分组和采样的所有价格

var sampled = source
    .GroupBy(p => p.Key)
    .SelectMany(o => o.Sample(TimeSpan.FromSeconds(1)));
如果某个价格在最后一秒钟内没有收到消息,则不包括在内

如果您希望包含旧价格,这将起作用:

var sampled2 = source
    .Scan(ImmutableDictionary<int, Price>.Empty, (state, p) => state.SetItem(p.Key, p))
    .Replay(1)
    .RefCount();
var dummySubscription = sampled2.Subscribe();
var result = Observable.Interval(TimeSpan.FromSeconds(1))
    .SelectMany(_ => sampled2.Take(1).SelectMany(state => state.Values));
var sampled2=源
.Scan(ImmutableDictionary.Empty,(state,p)=>state.SetItem(p.Key,p))
.重播(1)
.RefCount();
var dummySubscription=sampled2.Subscribe();
var结果=可观察的时间间隔(时间跨度从秒(1))
.SelectMany(=>sampled2.Take(1).SelectMany(state=>state.Values));

只要确保在处理
结果
observable时处理
DummySubscription

一个热的observable不会在内存中保留任何旧值,但您可以自己获取每个已知键的最后价格,例如在字典中

请参考以下示例代码

Dictionary<string, double> _prices = new Dictionary<string, double>();

GetPrices()
    .Buffer(TimeSpan.FromSeconds(1))
    .Subscribe(prices =>
    {
        if (prices != null && prices.Count > 0)
        {
            var grouped = prices.GroupBy(x => x.Key);
            foreach (var group in grouped)
                _prices[group.Key] = group.Last().Bid;
        }

        //print out the last quote of each known price key
        foreach (var price in _prices)
        {
            Console.WriteLine("Key: " + price.Key + ", last price: " + price.Value);
        }
    });
Dictionary\u prices=newdictionary();
GetPrices()
.缓冲区(时间跨度从秒(1))
.订阅(价格=>
{
if(prices!=null&&prices.Count>0)
{
var分组=价格.GroupBy(x=>x.Key);
foreach(分组中的var组)
_价格[group.Key]=group.Last().Bid;
}
//打印出每个已知价格键的最后报价
foreach(var价格单位价格)
{
Console.WriteLine(“键:+price.Key+”,最后一个价格:+price.Value);
}
});

它应该每秒打印每个已知键的最后一个引号。

hot observable不会在内存中保留任何旧值,但您可以自己获取每个已知键的最后一个价格,例如在字典中

请参考以下示例代码

Dictionary<string, double> _prices = new Dictionary<string, double>();

GetPrices()
    .Buffer(TimeSpan.FromSeconds(1))
    .Subscribe(prices =>
    {
        if (prices != null && prices.Count > 0)
        {
            var grouped = prices.GroupBy(x => x.Key);
            foreach (var group in grouped)
                _prices[group.Key] = group.Last().Bid;
        }

        //print out the last quote of each known price key
        foreach (var price in _prices)
        {
            Console.WriteLine("Key: " + price.Key + ", last price: " + price.Value);
        }
    });
Dictionary\u prices=newdictionary();
GetPrices()
.缓冲区(时间跨度从秒(1))
.订阅(价格=>
{
if(prices!=null&&prices.Count>0)
{
var分组=价格.GroupBy(x=>x.Key);
foreach(分组中的var组)
_价格[group.Key]=group.Last().Bid;
}
//打印出每个已知价格键的最后报价
foreach(var价格单位价格)
{
Console.WriteLine(“键:+price.Key+”,最后一个价格:+price.Value);
}
});

它应该每秒打印每个已知密钥的最后一个引号。

这是否符合您的要求

IObservable<ImmutableDictionary<string, Price>> sampled =
    Observable
        .Create<ImmutableDictionary<string, Price>>(o =>
        {
            var output = ImmutableDictionary<string, Price>.Empty;
            return
                source
                    .Do(x => output = output.SetItem(x.Key, x))
                    .Select(x => Observable.Interval(TimeSpan.FromSeconds(1.0)).Select(y => output).StartWith(output))
                    .Switch()
                    .Subscribe(o);
        });
IObservable采样=
可观察
.Create(o=>
{
var output=ImmutableDictionary.Empty;
返回
来源
.Do(x=>output=output.SetItem(x.Key,x))
.Select(x=>Observable.Interval(TimeSpan.FromSeconds(1.0)).Select(y=>output.StartWith(output))
.Switch()
.认购(o);
});

这是否符合您的要求

IObservable<ImmutableDictionary<string, Price>> sampled =
    Observable
        .Create<ImmutableDictionary<string, Price>>(o =>
        {
            var output = ImmutableDictionary<string, Price>.Empty;
            return
                source
                    .Do(x => output = output.SetItem(x.Key, x))
                    .Select(x => Observable.Interval(TimeSpan.FromSeconds(1.0)).Select(y => output).StartWith(output))
                    .Switch()
                    .Subscribe(o);
        });
IObservable采样=
可观察
.Create(o=>
{
var output=ImmutableDictionary.Empty;
返回
来源
.Do(x=>output=output.SetItem(x.Key,x))
.Select(x=>Observable.Interval(TimeSpan.FromSeconds(1.0)).Select(y=>output.StartWith(output))
.Switch()
.认购(o);
});

这是Shlomo的一个精巧版本,它使用
Scan
操作符和as状态保持每个键的最新值。下面的自定义运算符(
SampleByKey
)以特定间隔对一系列关键轴承元素进行采样。每次采样时,都会发出一个
IDictionary
,其中包含每个键迄今为止发出的最新值

public static IObservable<IDictionary<TKey, TSource>> SampleByKey<TSource, TKey>(
    this IObservable<TSource> source,
    Func<TSource, TKey> keySelector,
    TimeSpan interval,
    IEqualityComparer<TKey> keyComparer = default)
{
    return source
        .Scan(ImmutableDictionary.Create<TKey, TSource>(keyComparer),
            (dict, x) => dict.SetItem(keySelector(x), x))
        .Publish(published => Observable
            .Interval(interval)
            .WithLatestFrom(published, (_, dict) => dict)
            .TakeUntil(published.LastOrDefaultAsync()));
}
公共静态IObservable SampleByKey(
这是一个可观测的来源,
Func键选择器,
时间间隔,
IEqualityComparer键比较器=默认值)
{
返回源
.Scan(ImmutableDictionary.Create(keyComparer),
(dict,x)=>dict.SetItem(键选择器(x,x))
.Publish(published=>可观察
.间隔(间隔)
.WithLatestFrom(已出版,(u,dict)=>dict)
.TakeUntil(published.LastOrDefaultAsync());
}
用法示例:

IObservable<IDictionary<string, Price>> sampled = priceFeed
    .SampleByKey(p => p.Key, TimeSpan.FromSeconds(1.0));
IObservable sampled=priceFeed
.SampleByKey(p=>p.Key,TimeSpan.FromSeconds(1.0));
如果在两次采样期间,
发出零个元素,则将连续发出相同的字典

这个实现与我之前发布的一个非常类似,关于如何在动态变化的时间间隔内对序列进行采样

注意:我对以前的实现()进行了删减,认为它太复杂、太难实现