使用C#计算值在CSV文件中显示的次数

时间:2016-11-22 23:06:26

标签: c# linq csv datagridview

我有一个CSV文件,我想过滤这样的东西

我的CSV文件示例:

Name,LastName,Date
David,tod,09/09/1990
David,lopez,09/09/1994
David,cortez,09/09/1994
Maurice,perez,09/09/1980
Maurice,ruiz,09/09/1996

我想知道,在日期1(01/01/1990)和日期2(01/01/1999)之间出生了多少人(使用datetimepicker)

datagridview应该显示如下内容:

Name,Frecuency
David,3
Maurice,1

我不知道如何比较日期,但我有这个代码与linq逻辑

DataTable dtDataSource = new DataTable();

    dtDataSource.Columns.Add("Name");
    dtDataSource.Columns.Add("Frecuency");

    int[] array = new int[10];
    array[0] = 1;
    array[1] = 1;
    array[2] = 1;
    array[3] = 2;
    array[4] = 1;
    array[5] = 2;
    array[6] = 1;
    array[7] = 1;
    array[8] = 2;
    array[9] = 3;

    var group = from i in array
                group i by i into g
                select new
                {
                    g.Key,
                    Sum = g.Count()
                };

    foreach (var g in group)
    {

        dtDataSource.Rows.Add(g.Key,g.Sum);
    }







    if (dtDataSource != null)
    {


        dataGridViewReporte.DataSource = dtDataSource;

    }

谢谢!

1 个答案:

答案 0 :(得分:1)

在.NET中使用日期的最佳,最简单的方法是使用DateTimeOffset结构。这种类型公开了几种解析日期的方法(这使得从CSV文件中转换日期字符串变得容易),并且还可以使用标准运算符对日期进行简单比较。

请参阅DateTimeOffset documentation on MSDN

注意:.NET也有DateTime结构。我建议您尽可能使用DateTimeOffset,因为这有助于防止时区错误蔓延到您的代码中。

简单示例

作为一个简单示例,此代码演示了如何在.NET中将字符串解析为DateTimeOffset,然后将其与另一个日期进行比较。

// Static property to get the current time, in UTC.
DateTimeOffset now = DateTimeOffset.UtcNow;

string dateString = "09/09/1990";
DateTimeOffset date;

// Use TryParse to defensively parse the date.
if (DateTimeOffset.TryParse(dateString, out date))
{
    // The date is valid; we can use a standard operator to compare it.
    if (date < now)
    {
        Console.WriteLine("The parsed date is in the past.");
    }
    else
    {
        Console.WriteLine("The parsed date is in the future.");
    }
}

使用LINQ

示例代码中缺少的关键元素是LINQ表达式中的Where子句。现在我们已经看到了如何解析日期,只需将它们与您关心的开始和结束日期进行比较。

.Where(p => p.BirthDate >= startDate && p.BirthDate <= endDate)

注意:我发现当LINQ表达式被强类型化为某个对象时,它们非常适合使用。我在这个例子中包含了一个简单的Person类,希望能够大量清除代码。对于大多数情况,这应该没问题,但请记住,当您拥有批次数据时,LINQ-to-Objects虽然效率极高,但并不总是最有效的解决方案。

Person类:

class Person
{
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public DateTimeOffset BirthDate { get; set; }
}

示例代码:

// Representing the CSV file as an array of strings.
var csv = new []
{
    "Name,LastName,Date",
    "David,tod,09/09/1990",
    "David,lopez,09/09/1994",
    "David,cortez,09/09/1994",
    "Maurice,perez,09/09/1980",
    "Maurice,ruiz,09/09/1996"
};

// Parse each line of the CSV file into a Person object, skipping the first line.
// I'm using DateTimeOffset.Parse for simplicity, but production code should 
// use the .TryParse method to be defensive.
var people = csv
    .Skip(1)
    .Select(line =>
    {
        var parts = line.Split(',');
        return new Person
        {
            FirstName = parts[0],
            LastName = parts[1],
            BirthDate = DateTimeOffset.Parse(parts[2]),
        };
    });

// Create start and end dates we can use to compare.
var startDate = new DateTimeOffset(year: 1990, month: 01, day: 01, hour: 0, minute: 0, second: 0, offset: TimeSpan.Zero);
var endDate = new DateTimeOffset(year: 1999, month: 01, day: 01, hour: 0, minute: 0, second: 0, offset: TimeSpan.Zero);

// First, we filter the people by their birth dates.
// Then, we group by their first name and project the counts.
var groups = people
    .Where(p => p.BirthDate >= startDate && p.BirthDate <= endDate)
    .GroupBy(p => p.FirstName)
    .Select(firstNameGroup => new
    {
        Name = firstNameGroup.Key,
        Count = firstNameGroup.Count(),
    });

foreach (var group in groups)
{
    dtDataSource.Rows.Add(group.Name, group.Count);
}

LINQ语法

作为个人喜好,我通常使用LINQ扩展方法(.Where.Select.GroupBy等)而不是查询语法。按照上面示例中的样式,相同的查询可以写为:

var groups = from p in people
             where p.BirthDate >= startDate && p.BirthDate <= endDate
             group p by p.FirstName into g
             select new
             {
                 Name = g.Key,
                 Count = g.Count(),
             };