如何在c# linq中根据先前的数据创建与函数相关的新项

本文关键字:创建 数据 函数 新项 linq | 更新日期: 2023-09-27 18:02:10

List<History> data = new List<History>()
    {
        new History() {Symbol="a", Close = 1.0m, Date = new DateTime(2016, 2, 1) },
        new History() {Symbol="a", Close = 1.1m, Date = new DateTime(2016, 2, 2) },
        new History() {Symbol="a", Close = 1.4m, Date = new DateTime(2016, 2, 3) },
        new History() {Symbol="a", Close = 1.7m, Date = new DateTime(2016, 2, 4) },
        new History() {Symbol="a", Close = 1.8m, Date = new DateTime(2016, 2, 5) },
        new History() {Symbol="a", Close = 1.0m, Date = new DateTime(2016, 2, 7) },
        new History() {Symbol="a", Close = 1.1m, Date = new DateTime(2016, 2, 8) },
        new History() {Symbol="a", Close = 1.4m, Date = new DateTime(2016, 2, 9) },
        new History() {Symbol="a", Close = 1.7m, Date = new DateTime(2016, 2, 10) },
        new History() {Symbol="a", Close = 1.8m, Date = new DateTime(2016, 2, 11) },
        new History() {Symbol="b", Close = 1.6m, Date = new DateTime(2016, 2, 1) },
        new History() {Symbol="b", Close = 1.2m, Date = new DateTime(2016, 2, 2) },
        new History() {Symbol="b", Close = 1.4m, Date = new DateTime(2016, 2, 3) },
        new History() {Symbol="b", Close = 1.8m, Date = new DateTime(2016, 2, 4) },
        new History() {Symbol="b", Close = 1.2m, Date = new DateTime(2016, 2, 5) },
        new History() {Symbol="b", Close = 2.0m, Date = new DateTime(2016, 2, 7) },
        new History() {Symbol="b", Close = 1.4m, Date = new DateTime(2016, 2, 8) },
        new History() {Symbol="b", Close = 1.4m, Date = new DateTime(2016, 2, 9) },
        new History() {Symbol="b", Close = 1.0m, Date = new DateTime(2016, 2, 10) },
        new History() {Symbol="b", Close = 2.8m, Date = new DateTime(2016, 2, 11) },
        new History() {Symbol="c", Close = 2.0m, Date = new DateTime(2016, 2, 1) },
        new History() {Symbol="c", Close = 2.1m, Date = new DateTime(2016, 2, 2) },
        new History() {Symbol="c", Close = 1.4m, Date = new DateTime(2016, 2, 3) },
        new History() {Symbol="c", Close = 2.7m, Date = new DateTime(2016, 2, 4) },
        new History() {Symbol="c", Close = 1.2m, Date = new DateTime(2016, 2, 5) },
        new History() {Symbol="c", Close = 1.3m, Date = new DateTime(2016, 2, 7) },
        new History() {Symbol="c", Close = 2.2m, Date = new DateTime(2016, 2, 8) },
        new History() {Symbol="c", Close = 1.3m, Date = new DateTime(2016, 2, 9) },
        new History() {Symbol="c", Close = 2.6m, Date = new DateTime(2016, 2, 10) },
        new History() {Symbol="c", Close = 1.9m, Date = new DateTime(2016, 2, 11) },
    };
var StockGroupList = data
           .GroupBy(o => o.Symbol)
           .OrderBy(o => o.Key)
           .ToList();

我想创建一个像

这样的新列表
select new { Symbol, Close, Date, Vol};

这里Vol是五天的标准差,例如Symbol="a"2016, 2, 5Vol2016, 2, 12016, 2, 5close的函数,前四天的Vol(例如2016, 2, 12016, 2, 4)默认为Vol = 0

预期输出:

List<dynamic> NewData = new List<dynamic>
{ 
       new History() {Symbol="a", Close = 1.0m, Date = new DateTime(2016, 2, 1), Vol = 0 },
       new History() {Symbol="a", Close = 1.1m, Date = new DateTime(2016, 2, 2), Vol = 0 },
       new History() {Symbol="a", Close = 1.4m, Date = new DateTime(2016, 2, 3), Vol = 0 }, 
       new History() {Symbol="a", Close = 1.7m, Date = new DateTime(2016, 2, 4), Vol = 0 },
       new History() {Symbol="a", Close = 1.8m, Date = new DateTime(2016, 2, 5), Vol = SD(XXX) }, 
       new History() {Symbol="a", Close = 1.0m, Date = new DateTime(2016, 2, 7), Vol = SD(XXX) },
                                ......
};

你可以把SD(xxx)看作一个给定的函数,简单地表示十天的总和,但不要使用逐条输入的方法,因为实际上这里ten可能会被大数据中的一个大数代替。此外,如果SD遵循表单

using MathNet.Numerics.Statistics;
decimal OneStdDev = (decimal)(new DescriptiveStatistics(data.Select(o => (double)o.Close)).StandardDeviation);

我该怎么办?

如何在c# linq中根据先前的数据创建与函数相关的新项

我不确定我是否理解对了,但我认为你正在寻找这样的东西。(为了简单起见,我用Average函数代替了StdDev函数)。

int dayspan = 5;
var result = from history in data
    let lastCloses =
            from history1 in data
            where history.Symbol == history1.Symbol 
                && history.Date >= history1.Date 
                && history.Date - history1.Date <= TimeSpan.FromDays(dayspan)
            select history1.Close
    select new {
        Symbol = history.Symbol, 
        Close = history.Close, 
        Date = history.Date, 
        Vol = lastCloses.Count() >= dayspan ? lastCloses.Average() : 0};
更新:

如果不能依赖日期而想使用列表位置,则不能使用Linq查询语法,而是使用Linq方法语法:

int dayspan = 5;
var result = data.Select(
    delegate(History history, int index)
    {
        decimal[] vol = data
                .Select((history1, index1) => new {History = history1, Index = index1})
                .Where(x => x.Index <= index 
                    && index - x.Index < dayspan 
                    && x.History.Symbol == history.Symbol)
                .Select(x => x.History.Close).ToArray();
        return new
        {
            Symbol = history.Symbol,
            Close = history.Close,
            Date = history.Date,
            Vol = vol.Count() == dayspan ? vol.Average() : 0
        };
    });

出于可读性的考虑,也许使用简单的循环来解决这个问题比Linq:-)

更好。