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

And*_* P. 2 c# linq time-series ranking

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

  1. 为每个安全性创建一个新的空时间序列[日期,(整数)排名],以在给定日期保持其排名.这可以是a的形式SortedList<DateTime,double>.
  2. 创建了所有唯一日期的列表(并非每个证券的时间序列都具有每个日期的值.)
  3. 对于每个独特的日期,循环每个证券的每日流动性时间序列,以确定它是否具有该日期的值.
  4. 如果是,请将证券名称和值添加到每日排名数组[SecName,流动性值].
  5. 将数组从最大到最小排序(排名1 =最大值).
  6. 对于阵列中的每个安全性(secName),将日期和证券的等级添加到其时间序列(在步骤1中创建).

简而言之,这是每日流动性从最大到最小的排名.我可以让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;
        }

    }
}
Run Code Online (Sandbox Code Playgroud)

像这样使用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);
        }
    }
Run Code Online (Sandbox Code Playgroud)

应该如下......

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
Run Code Online (Sandbox Code Playgroud)

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

Jon*_*eet 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 });
Run Code Online (Sandbox Code Playgroud)

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

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