编辑:在09/15/2013-我正在描述我的情况,进一步分解为可帮助大家更好地了解我的情况的步骤。也添加了整个应用程序的源代码以供下载。如果要跳到原始问题,请向下滚动到最后一个标题。请让我知道问题。谢谢

概括

阿拉斯加州首府朱诺市有一个AST(阿拉斯加州州骑兵)总部大楼,他们希望在这里显示一个大屏幕,上面显示一个数字并自动更新。该数字称为(犯罪商指数)或CQI

CQI基本上是一个计算得出的数字,用以显示该州的当前犯罪情况。

它是如何计算的?

运行该屏幕的程序是一个.NET WPF应用程序,该应用程序通过IObservable热流不断接收CrimeReport对象。

计算每个城市的CQI,然后取所有城市的Sum(),称为州CQI
这是计算状态CQI的步骤

步骤1-接收犯罪数据

每次报告犯罪时,都会将CrimeReport发送到.NET应用程序。它具有以下组成部分

犯罪日期

市-市/县

严重级别-严重/严重

EstimatedSolveTime-AST确定解决犯罪所需的估计天数。

因此,在这一步中,我们订阅IObservable并创建MainViewModel实例

IObservable<CrimeReport> reportSource = mainSource.Publish();
  MainVM = new MainViewModel(reportSource);
reportSource.Connect();

第2步-按城市分组并按城市进行数学运算

收到报告后,请按城市将其分组
var cities = reportSource.GroupBy(k => k.City)
                  .Select(g => new CityDto(g.Key, g);

CityDto是DTO类,它获取当前城市的所有报告并计算城市的CQI。

通过以下公式计算城市的CQI



这是CityDto的类定义
internal class CityDto
{
 public string CityName { get; set; }
 public IObservable<decimal> CityCqi {get; set;}

 public CityDto(string cityName, IObservable<CrimeReport> cityReports)
 {
   CityName = cityName;
   // Get all serious and non serious crimes
   //
     var totalSeriousCrimes = cityReports.Where(c => c.Severity == CrimeSeverity.Serious)
     .Scan(0, (p, _) => p++);
     var totalnonSeriousCrimes = cityReports.Where(c => c.Severity == CrimeSeverity.NonSerious)
     .Scan(0, (p, _) => p++);

     // Get the ratio
     //
     var ratio = Observable.CombineLatest(totalSeriousCrimes, totalnonSeriousCrimes,
                   (s, n) => n ==  0? s : s/n); // Avoding DivideByZero here

     // Get the minimum and maximum estimated solve time
     //
       var minEstimatedSolveTime = cityReports.Select(c => c.EstimatedSolveTime)
                     .Scan(5000, (p, n) => n < p? n : p);
       var maxEstimatedSolveTime = cityReports.Select(c=>c.EstimatedSolveTime)
                     .Scan(0, (p, n) => n > p? n : p);

    //Time for the City's CQI
    //
      CityCqi = Observable.CombineLatest(ratio, minEstimatedSolveTime, maxEstimatedSolveTime, (r, n, x) => r < 1.0? r * n : r * m);
 }
}

现在我们有了City DTO对象,可以维护City的CQI值并通过IObservable公开实时的CQI,阿拉斯加州首府想将所有城市的CQI求和(显示)为阿拉斯加的CQI并在屏幕上实时显示,每个在参与CQI计划的市/县中任何地方报告的犯罪应立即对该州的CQI产生影响

第3步-汇总城市的状态数据

现在我们要计算在大屏幕上实时更新的整个州的CQI,我们有一个称为MainViewModel的州 View 模型
internal class MainViewModel
{
    public MainViewModel(IObservable<CrimeReport> mainReport)
    {
         /// Here is the snippet also mentioned in Step 2
         //
           var cities = mainReport.GroupBy(k => k.City)
                  .Select(g => new CityDto(g.Key, g));

         ///// T h i s ///// Is //// Where //// I /// am /// Stuck
         //
          var allCqis = cities.Select(c => c.CityCqi); // gives you IObservable<IObservable<decimal>> ,

         /// Need to use latest of each observable in allCqi and sum them up
           //// How do I do it ?
     }
}

约束条件
  • 并非阿拉斯加的所有城市目前都在参加该州的CQI计划,但是城市每天都在招生,因此我无法拥有List,并且添加所有城市(无论是否招募)也不可行。因此,IObservable不仅维护那些参与的城市,而且还至少发送了一个CrimeReport对象。

  • 完整的源代码

    可以通过单击Here下载源

    最初提出的问题

    我有一个热观测值,有多个热观测值...
    IObservable<IObservable<decimal>>
    

    我想要一个可观察的对象,当订阅时,它将使观察者知道内部所有可观察对象的所有“最新”十进制数字的总和。

    我该如何实现?我尝试了CombineLatest(...),但无法正确执行。

    谢谢

    最佳答案

    Rxx库具有CombineLatest()重载的IObservable<IObservable<T>>。如果使用此重载,则解决方案很简单:

    var runningSum = allCqis
        .Select(cqi => cqi.StartWith(0)) // start each inner sequence off with 0
        .CombineLatest() // produces an IObservable<IList<decimal>>
        .Select(cqis => cqis.Sum()); // LINQ operator Sum(IEnumerable<decimal>)
    

    查看Rxx.CombineLatest的源代码对于查看如何“深入了解”问题可能很有用。

    关于c# - 如何获取N个热门Observable <decimal>实例的 “last”项的总和?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/18800914/

    10-11 20:04