如何在列表中的特定列中的两行之间进行计算

时间:2015-02-11 13:31:09

标签: c# csv

我有这段代码:

using System;
using System.Collections.Generic;
using System.Linq;
using System.IO;

namespace CsvDemo
{
class Program
{
    static void Main(string[] args)
    {
        List<DailyValues> values = File.ReadAllLines("C:\\Users\\Josh\\Sample.csv")
                                       .Skip(1)
                                       .Select(v => DailyValues.FromCsv(v))
                                       .ToList();
    }
}

class DailyValues
{
    DateTime Date;
    decimal Open;
    decimal High;
    decimal Low;
    decimal Close;
    decimal Volume;
    decimal AdjClose;

    public static DailyValues FromCsv(string csvLine)
    {
        string[] values = csvLine.Split(',');
        DailyValues dailyValues = new DailyValues();
        dailyValues.Date = Convert.ToDateTime(values[0]);
        dailyValues.Open = Convert.ToDecimal(values[1]);
        dailyValues.High = Convert.ToDecimal(values[2]);
        dailyValues.Low = Convert.ToDecimal(values[3]);
        dailyValues.Close = Convert.ToDecimal(values[4]);
        dailyValues.Volume = Convert.ToDecimal(values[5]);
        dailyValues.AdjClose = Convert.ToDecimal(values[6]);
        return dailyValues;
        }
    }
}
  1. File.ReadAllLines将CSV文件中的所有行读取为字符串数组。
  2. .Skip(1)会跳过标题行。
  3. .Select(v => DailyValues.FromCsv(v))使用Linq选择每一行,并使用DailyValues方法创建新的FromCsv实例。这会创建System.Collections.Generic.IEnumerable<CsvDemo.DailyValues>类型。
  4. 最后,.ToList()将IEnumerable转换为List以匹配您想要的类型。
  5. 但我的问题是如何在两个单元格之间进行计算。例如,我想在第3列中添加第2行和第3行,结果将显示在最后一列中。

3 个答案:

答案 0 :(得分:1)

看起来(虽然,我依赖于这里的一些思维读法)你试图在列表的每个记录上都有一个运行平衡字段。您已经拥有将原始csv数据投影到对象列表中的代码:

List<DailyValues> values = File.ReadAllLines("C:\\Users\\Josh\\Sample.csv")
                                   .Skip(1)
                                   .Select(v => DailyValues.FromCsv(v))
                                   .ToList()

你需要做的就是将它再次投射到另一个列表中,随时进行计算。显然,这个计算不能对第一行做任何事情,因为它需要一个先前的值,所以在那个实例中你将它设置为零。

class DailyValuesWithTotal : DailyValues
{
    decimal TotalHigh
}
var projectedValues = values.Select( (v,i) => new DailyValuesWithTotal(){
    Date = v.Date,
    Open = v.Open,
    High = v.High,
    Low = v.Low,
    Volume = v.Volume,
    AdjClose = v.AdjClose,       
    TotalHigh = (i == 0) ? 0.0 : values[i-1].TotalHigh + v.High
})

上面的示例在名为High的新字段中保留TotalHigh字段的总计。

答案 1 :(得分:0)

如果我正确理解了您的问题,您希望将当前行和下一行的值相加到当前行的最后一列。

如果这是正确的,您可以在读取文件中的所有数据后使用for循环执行此操作。只需在您的类中添加一个属性,您将填充该循环。

答案 2 :(得分:0)

首先,我建议使用FileHelpers或其他CSV解析库,因为它会使您的代码更容易(尤其是错误处理,处理引号等)。

(我会在答案中使用这个库,但你不必这样做)

向您的类添加新属性以存储计算值:

[IgnoreFirst(1)] 
[DelimitedRecord(",")]
class DailyValues
{
    [FieldConverter(ConverterKind.Date, "yyyy-MM-dd")] 
    public DateTime Date;
    public decimal Open;
    public decimal High;
    public decimal Low;
    public decimal Close;
    public decimal Volume;
    public decimal AdjClose;
    [FieldNotInFile] 
    public decimal SomethingCalculated;
}

然后循环遍历元素并使用临时变量来跟踪您感兴趣的上一个元素的值,以便进行计算:

var engine = new FileHelperEngine(typeof(DailyValues));
var res = engine.ReadFile(@"your:\path") as DailyValues[]; 

decimal? prev = null;
foreach(var value in res)
{
    if(prev.HasValue)
        // or whatever columns you want to use
        value.SomethingCalculated = value.High + prev.Value;
    prev = value.Open;
}