简体   繁体   English

如何得到N hot Observable的“最后”项目的总和 <decimal> 实例?

[英]How to get Sum of “last” items of N hot Observable<decimal> instances?

EDIT: On 09/15/2013 - I am describing my scenario further broken into steps to help everybody understand my situation better. 编辑:2013年9月15日 - 我正在描述我的情景进一步分解为帮助每个人更好地了解我的情况的步骤。 Added the source for whole application for download too. 添加了整个应用程序的源代码以供下载。 If you want to jump to the original question, scroll down to the last heading. 如果要跳转到原始问题,请向下滚动到最后一个标题。 Please let me know the questions. 请让我知道这些问题。 Thanks 谢谢

Summary 摘要

Alaska state Capital Juneau has a AST (Alaska State Trooper) headquarters building where they would like to show a large screen with a single number displayed and updated automatically. 阿拉斯加州首府朱诺有一个AST(阿拉斯加州警官)总部大楼,他们希望在这个大屏幕上显示一个显示和自动更新的单个号码。 That number is called (Crime Quotient Index) or CQI 该号码称为(犯罪商数指数)或CQI

CQI is basically a calculated number to show the current crime situation of the state... CQI基本上是一个计算出的数字,用于显示当前的国家犯罪情况......

How it is calculated? 如何计算?

The program that runs the screen is a .NET WPF Application that is constantly receiving CrimeReport objects through a Hot IObservable stream. 运行屏幕的程序是.NET WPF应用程序,它通过Hot IObservable流不断接收CrimeReport对象。

CQI is calculated per city and then a Sum() for all cities is taken which is called States CQI Here are the steps of calculating the State CQI 每个城市计算CQI,然后采用所有城市的Sum(),称为国家CQI以下是计算国家CQI的步骤

Step 1 - Receive crime data 第1步 - 接收犯罪数据

CrimeReport is sent to the .NET Application each time a crime is reported. 每次报告犯罪时,CrimeReport都会发送到.NET应用程序。 It has the following components 它具有以下组件

DateTime of the crime 犯罪日期时间

City - City/County of Jurisdiction - 市/辖县

SeverityLevel - Serious/NonSerious SeverityLevel - 严肃/非严重

EstimatedSolveTime - Estimated number of days AST determines it would take to solve the crime. EstimatedSolveTime - AST确定解决犯罪所需的预计天数。

So in this step, we subscribe to the IObservable and create instance of MainViewModel 因此,在此步骤中,我们订阅了IObservable并创建了MainViewModel的实例

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

Step 2 - Group by city and do maths per city 第2步 - 逐个城市,每个城市做数学

As you receive the Report, group it by city so 当您收到报告时,请按城市进行分组

var cities = reportSource.GroupBy(k => k.City)
                  .Select(g => new CityDto(g.Key, g);

CityDto is a DTO class that takes all its report for current city and calculates the City's CQI. CityDto是一个DTO课程,它接收当前城市的所有报告并计算城市的CQI。

The calculation of City's CQI is done by the following formula 城市CQI的计算通过以下公式完成

if Ratio of Total number serious crimes to Total number of Non serious crimes is less than 1 如果严重犯罪总数与非严重犯罪总数之比小于1

then 然后

City's CQI = Ratio x Minimum of Estimated Solve time 城市的CQI =比率x估计求解时间的最小值

else 其他

City's CQI = Ratio x Maximum Estimated Solve time 城市的CQI =比率x最大估计求解时间

Here is class definition of CityDto 这是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);
 }
}

Now that we have City DTO objects maintaining City's CQI values and exposing that live CQI through an IObservable, Alaska State's Capital would like to Sum() up all the Cities' CQI to show it as Alaska's CQI and show it live on the screen and Each crime reported anywhere in the City/County participating in CQI program should have an immediate effect on the State's CQI 现在我们有城市DTO对象维护城市的CQI值并通过IObservable暴露实时CQI,阿拉斯加州的Capital希望Sum()将所有城市的CQI显示为阿拉斯加的CQI并在屏幕上显示它们在参与CQI计划的城市/县的任何地方报告的犯罪应立即对国家的CQI产生影响

Step 3 - Roll up cities' data for state 第3步 - 为州填写城市数据

Now we have to calculate the whole state's CQI which is live updating on the big screen, we have State's view model called MainViewModel 现在我们必须计算整个州的CQI,这是大屏幕上的实时更新,我们有State的视图模型,名为MainViewModel

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 ?
     }
}

Constraints 约束

  • Not all cities in Alaska currently participate in state's CQI program, but cities are enrolling day by day so I cannot have List and adding all the cities regardless of enrollment is not practical either. 并非所有阿拉斯加城市都参与州的CQI计划,但城市正在日复一日地注册,因此我无法列出并添加所有城市,无论注册是否也不实用。 So it is IObservable which maintains only those cities not only participating but also have sent at least one CrimeReport object. 所以它是IObservable,它只维护那些不仅参与但也发送了至少一个CrimeReport对象的城市。

Full Source code 完整源代码

Source can be downloaded by clicking Here 点击此处即可下载来源

Originally asked question 原来问的问题

I have a single hot observable of multiple hot observables... 我有一个热的可观察的多个热观察点......

IObservable<IObservable<decimal>>

I would like an observable that when subscribed will keep its observer informed of the sum of all "Latest" decimal numbers from all observables inside. 我想要一个可观察到的,当订阅时会让观察者知道里面所有可观察者的所有“最新”十进制数的总和。

How can I achieve that ? 我怎样才能做到这一点? I tried CombineLatest(...) but could not get it right. 我尝试过CombineLatest(...)但是无法正确使用它。

Thanks 谢谢

The Rxx library has an overload of CombineLatest() which takes an IObservable<IObservable<T>> . Rxx库有一个CombineLatest()的重载,它接受一个IObservable<IObservable<T>> If you use this overload, then the solution is easy: 如果您使用此过载,则解决方案很简单:

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>)

Looking at the source code for Rxx.CombineLatest might be useful to see how the problem is solved "under the hood" 查看Rxx.CombineLatest的源代码可能有助于了解问题如何在“引擎盖下”解决

Lots of questions! 很多问题! Maybe time to brush up on your Rx skillz? 也许是时候了解你的Rx技巧? Pretty much all of your recent questions are covered in my web site IntroToRx.com . 几乎所有最近的问题都在我的网站IntroToRx.com中介绍 Having a deep understanding of Rx, will allow you to answer these fairly simple questions much more quickly than asking on a forum. 深入了解Rx,可以比在论坛上提问更快地回答这些相当简单的问题。 You should be able to read the book in less than 3 days. 你应该可以在不到3天的时间内阅读这本书。

Anyway.... 无论如何....

1 Do you want a running sum or just a single sum at the end? 1你想要一笔运行金额或者最后一笔金额吗?

2 Then, do you want a sum for all values for all streams, or the sums of each stream? 2那么,您是否想要所有流的所有值或每个流的总和的总和?

To get a single sum value for a sequence you use the .Sum() operator. 要获取序列的单个和值,请使用.Sum()运算符。 http://introtorx.com/Content/v1.0.10621.0/07_Aggregation.html#MaxAndMin http://introtorx.com/Content/v1.0.10621.0/07_Aggregation.html#MaxAndMin

To get a running total, use the Scan operator. 要获得运行总计,请使用“ Scan运算符。 http://introtorx.com/Content/v1.0.10621.0/07_Aggregation.html#Scan http://introtorx.com/Content/v1.0.10621.0/07_Aggregation.html#Scan

So the answer is probably something like this (untested): 所以答案可能是这样的(未经测试):

sources.Select(source=>source.Scan(0m, (acc, value)=>acc+=value)).Merge();

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM