我有一个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;
}
谢谢!
答案 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表达式中的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扩展方法(.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(),
};