【问题标题】:Calculating the average of a column in a CSV file using linq c#使用linq c#计算CSV文件中列的平均值
【发布时间】:2018-08-10 10:45:32
【问题描述】:

我对 c# 很陌生,但我真的很想开始使用 linq 从 excel 电子表格中提取简单信息。

问这个我觉得很尴尬,但我似乎找不到解决办法。基本上,我想要的只是在 CSV 文件中找到捐赠金额的平均值。

到目前为止,这是以下代码:

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace CSharpTest
{
    class Program
{
    public string Donor { get; set; }
    public DateTime Date { get; set; }
    public decimal Amount { get; set; }
    public string Charity { get; set; }

    static void Main(string[] args)
    {
        {

            var file = "C:\\Users\\user\\Desktop\\Donations.csv".AsFile();

            File.ReadAllLines(file).Select(x => x.Split('\n')).Average(x => x.Count());


        }

    }
}

问题是我知道这是错误的,因为我只想要 Amount 中的值。对于这样的事情,我确信我应该使用 GroupBy(),但是我似乎无法提取公共类 Amount。如果有人能指出我正确的方向,我将不胜感激。非常感谢。

【问题讨论】:

  • CSV Helper的时间?
  • 您要的是每人的平均值还是整个文件的平均值?如果您想要每人或某事的平均值,您只需要分组。如果您只想要整列的平均值,则不需要分组。您需要做的是拆分, 上的每一行(而不是\n - 您已经有行),获取第三项(金额),将其解析为数字类型(例如十进制),然后应用您的平均运营商。正如其他人所说,使用 CSV 解析器可以使其中几个步骤变得更容易。
  • 我一定会看看 CSV 助手,非常感谢 - @DragandDrop
  • 我只是在平均一个整体之后,抱歉没有更清楚。哦,当然分开,会更有意义。当你说采取第三项时,它会是这样的:.Select(x => x[2] .....?然后它会给出一个 TryParseAs()。非常感谢@Chris 的帮助
  • @DanielLee:基本上是的,获得第三个项目将通过x[2] 或类似的方式完成。但是,请务必使用 CSV 解析器阅读以下答案。它们通常更好用。例如,如果您的第一列具有诸如“Smith, John”之类的值,那么您仅使用逗号分割的方法将不再有效,因为您需要担心该字段如何转义该逗号。使用 CSV 解析器是解决问题的更可靠的解决方案。

标签: c# excel linq file csv


【解决方案1】:

创建一个对象模型来保存数据是一个好的开始

public class Donation {
    public string Donor { get; set; }
    public DateTime Date { get; set; }
    public decimal Amount { get; set; }
    public string Charity { get; set; }
}

接下来您要解析 CSV 文件中的数据。

CSVHelper 之类的内容有助于将数据解析为可用对象。

var textReader = new StreamReader("C:\\Users\\user\\Desktop\\Donations.csv");
var csv = new CsvReader( textReader );
var records = csv.GetRecords<Donation>();

从那里使用 LINQ 计算平均值很简单,只需调用已解析集合的扩展方法即可。

var average = records.Average(_ => _.Amount);

【讨论】:

  • 这确实让事情看起来容易多了,我一定会看看的,非常感谢!!!
【解决方案2】:

如果像Nkosi's answer 中的CSVHelper 这样的外部库是不可能的,您可以保持相同的原则,但手动解析它:

public class Model
{
    public int Id { get; set; }
    public string Donor { get; set; }
    public DateTime Date { get; set; }
    public decimal Amount { get; set; }
    public string Charity { get; set; }
}


string csv =  File.ReadAllText(file);

//skip(1), for hearder
var lines = csv.Split(new char[] {'\n'}, StringSplitOptions.RemoveEmptyEntries).Skip(1);
List<Model> models = new List<Model>();

int id=1;
foreach (var item in lines)
{
    var values = item.Split(',');
    if(values.Count()!= 4) continue;//error loging

    var model = new Model
    {
        Id = id,
        Donor = values[0],
        Date = DateTime.Parse(values[1]),
        Amount = Decimal.Parse(values[2]),
        Charity = values[3]
    };

    models.Add(model);

    id++;
}

现在你可以轻松地 linq:

var result = models.Average(x=> x.Amount);

平均每人

var avgPerPerson = models 
                    .GroupBy(x=> x.Donor)
                    .Select(g=> new {
                      Donor = g.Key,
                      Average = g.Average(c => c.Amount)
                    });

【讨论】:

    【解决方案3】:
    var total = 0.0d;
    foreach (var line in File.ReadLines(//FilePath))
    {
        var lineArr = line.Split(',');
    
        double lineDonation;
        if (double.TryParse(lineArr[2])
            total += lineDonation;
    }
    

    【讨论】:

      【解决方案4】:

      您可以将 Microsoft Excel 包“Microsoft.Office.Interop.Excel”。您可以从 Nuget 轻松下载:

          static void Main(string[] args)
          {
              Microsoft.Office.Interop.Excel.Application xlsApp = new Microsoft.Office.Interop.Excel.Application();
      
              if (xlsApp == null)
              {
                  //Any message
              }
      
              Workbook wb = xlsApp.Workbooks.Open("C:\\Users\\310231566\\Downloads\\main.xlsx",
                  0, true, 5, "", "", true, XlPlatform.xlWindows, "\t", false, false, 0, true);
              Sheets sheets = wb.Worksheets;
              Worksheet ws = (Worksheet)sheets.get_Item(1);
      
              Range firstColumn = ws.UsedRange.Columns[1];
              System.Array myvalues = (System.Array)firstColumn.Cells.Value;
              string[] strArray = myvalues.OfType<object>().Select(o => o.ToString()).ToArray();
              int j = 0;
              int avg = 0;
              int[] intArray = new int[strArray.Length-1];
              for (int i = 1; i < strArray.Length; i++)
              {
                  intArray[j] = int.Parse(strArray[i]);
                  avg  = avg + intArray[j];
                  j++;
              }
      
              avg = avg/intArray.Length;
          }
      

      【讨论】:

      • 这肯定不是我遇到过的,一定会看看尝试理解的,非常感谢
      • 好的,如果您在执行此代码时需要任何帮助,请告诉我
      【解决方案5】:

      每个在线捐赠者的平均数量,没有故障保护:

      var avg =  File
              .ReadAllLines(file)
              .Skip(1)
              .Select(x => x.Split(','))
              .Select((x,i) => new {
                      Donor = values[0],
                      Amount = Decimal.Parse(values[2])
                  })
              .GroupBy(x=> x.Donor)
              .Select(g=> new {
                Donor = g.Key,
                AverageAmount = g.Average(c => c.Amount)
              });
      

      【讨论】:

      • 谢谢你,我也试试看!
      猜你喜欢
      • 2015-01-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-02-16
      • 2014-05-30
      • 1970-01-01
      • 2011-02-12
      相关资源
      最近更新 更多