C#LINQ每日对时间序列值进行排名=>按日期划分,然后按值排序(从最大到最小)

时间:2011-03-08 07:38:23

标签: c# linq ranking time-series

我有SortedList<DateTime,double>形式的大约2000个单独的时间序列。每个系列对应于给定证券的每日流动性。我想创建这些值的每日排名。如果我用for循环执行此操作,我会执行以下操作:

  1. 为每个证券创建一个新的空时间序列[日期,(整数)排名],以在给定日期保持其排名。这可以是SortedList<DateTime,double>
  2. 的形式
  3. 创建了所有唯一日期的列表(并非每个证券的时间序列都包含每个日期的值。)
  4. 对于每个独特日期,循环浏览每个证券的每日流动性时间序列,以确定它是否具有该日期的值。
  5. 如果是,请将证券名称和值添加到每日排名数组[SecName,流动性值]。
  6. 将数组从最大值排序到最小值(排名1 =最大值)。
  7. 对于阵列中的每个安全性(secName),将日期和证券的等级添加到其时间序列(在步骤1中创建)。
  8. 简单来说,这是每日流动性从最大到最小的排名。我可以让linq从对象中提取数据并按日期分组,但其余的超出了我的linq技能。

    任何linq大师都会照顾这个?

    下面概述了对象结构的简化版本。

    注意:我有意创建了一个日期(2011,01,18),其中值(30)是相同的。在这种情况下,符号名称的子排名是可接受的。所以他们将排名第一名6753 JT,第二名6754 JT。 6752 JT没有该日期的值,因此不会包含它。

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    
    namespace Ranking_Query
    {
        class Program
        {
            static void Main(string[] args)
            {
                // created an instance of the datasource and add 3 securities to it
                Datasource ds = new Datasource() { Name = "test" };
    
                ds.securities.Add("6752 JT", new Security() { 
                    timeSeries = new Dictionary<string, SortedList<DateTime, double>>() {
                        { "liquidity", new SortedList<DateTime, double>() { 
                            {new DateTime(2011,01,15),30},
                            {new DateTime(2011,01,16),20},
                            {new DateTime(2011,01,17),10} } } }
                });
    
                ds.securities.Add("6753 JT", new Security()
                {
                    timeSeries = new Dictionary<string, SortedList<DateTime, double>>() {
                        { "liquidity", new SortedList<DateTime, double>() { 
                            {new DateTime(2011,01,15),20},
                            {new DateTime(2011,01,16),30},
                            {new DateTime(2011,01,17),20},
                            {new DateTime(2011,01,18),30} } } }
                });
    
                ds.securities.Add("6754 JT", new Security()
                {
                    timeSeries = new Dictionary<string, SortedList<DateTime, double>>() {
                        { "liquidity", new SortedList<DateTime, double>() { 
                            {new DateTime(2011,01,16),10},
                            {new DateTime(2011,01,17),30},
                            {new DateTime(2011,01,18),30} } } }
                });
    
    
            }
    
            class Datasource
            {
                public string Name { get; set; }
                public Dictionary<string, Security> securities = new Dictionary<string, Security>();
            }
    
            class Security
            {
                public string symbol { get; set; }
                public Dictionary<string, SortedList<DateTime, double>> timeSeries;
            }
    
        }
    }
    

    使用这样的foreach循环输出......

        foreach (var sec in rankingsBySymbol)
        {
            Console.WriteLine(sec.Key);
            foreach (var secRank in sec)
            {
                Console.WriteLine("  {0} value {1} rank {2}",secRank.Date, secRank.Value, secRank.Rank);
            }
        }
    

    应该如下......

    6752 JT
      1/15/2011 12:00:00 AM value 30 rank 1
      1/16/2011 12:00:00 AM value 20 rank 2
      1/17/2011 12:00:00 AM value 10 rank 3
    6753 JT
      1/15/2011 12:00:00 AM value 20 rank 2
      1/16/2011 12:00:00 AM value 30 rank 1
      1/17/2011 12:00:00 AM value 20 rank 2
      1/18/2011 12:00:00 AM value 30 rank 1
    6754 JT
      1/16/2011 12:00:00 AM value 10 rank 3
      1/17/2011 12:00:00 AM value 30 rank 1
      1/18/2011 12:00:00 AM value 30 rank 2
    

    注意:最终输出不需要包含用于计算排名的初始值,只需包括日期和排名。我已将其包括在内,因为它可以更容易理解最初的问题。

1 个答案:

答案 0 :(得分:5)

您的数据结构并不十分清楚,但我想您需要的内容如下:

// Initial query just to get a sequence of { Symbol, Date, Value } entries.
var entries = from securityPair in ds.securities
              from valuation in securityPair.Value.timeSeries["liquidity"]
              select new { Symbol = securityPair.Key,
                           Date = valuation.Key,
                           valuation.Value };

// Now do the grouping, sorting and ranking
var groupedByDate = from entry in entries
                    group entry by entry.Date into date
                    select date.OrderByDescending(x => x.Value)
                               .ThenBy(x => x.Symbol)
                               // Use the overload of Select which includes the
                               // index within the sequence (*after* sorting)
                               .Select((x, index) => new {
                                    x.Symbol,
                                    x.Value,
                                    x.Date,
                                    Rank = index + 1,
                                });

// Now group by symbol again
var rankingsBySymbol = groupedByDate.SelectMany(day => day)
                                    .ToLookup(tuple => tuple.Symbol,
                                              tuple => new { tuple.Date,
                                                             tuple.Value,
                                                             tuple.Rank });

这将按符号构建一个查找,其中每个符号将包含该符号的值和该日期的排名的结果列表(按日期顺序排列)。

至少,这是计划。我根本没有测试过这个......