2011-03-16 41 views
4

以下LINQ查询读取分隔文件并返回每个recordId的最近记录。问题是,最新的记录并不总是被返回。我究竟做错了什么?我需要更改哪些内容以确保始终返回最近的日期?有没有比使用.Max()更好的方法?为什么这个LINQ查询不能返回正确的日期?

我还附加了一些示例数据,以便您可以看到问题。查看示例数据时,标有星号(*)的行是我想返回的行(最近的日期)。标有X的行在我看来是错误的返回。

在多次出现相同的recordId(例如#162337)并且有多个日期的情况下,我希望返回一个带有最近日期的记录。

var recipients = File.ReadAllLines(path) 
    .Select (record => record.Split('|')) 
    .Select (tokens => new 
     { 
     FirstName = tokens[2], 
     LastName = tokens[4], 
     recordId = Convert.ToInt32(tokens[13]), 
     date = Convert.ToDateTime(tokens[17]) 
     } 
    ) 
    .GroupBy (m => m.recordId) 
    .OrderByDescending (m => m.Max (x => x.date)) 
    .Select (m => m.First()) 
    .OrderBy (m => m.recordId) 

    .Dump(); 


FirstName LastName recordId date  
fname lname 137308 2/15/1991 0:00 
fname lname 138011 6/16/1983 0:00 * 
fname lname 138011 11/9/1981 0:00 x 
fname lname 158680 9/4/1986 0:00 
fname lname 161775 4/23/1991 0:00 
fname lname 162337 12/1/1998 0:00 * 
fname lname 162337 12/1/1998 0:00 * 
fname lname 162337 9/1/1994 0:00 x 
fname lname 162337 9/1/1994 0:00 x 
fname lname 163254 2/12/1969 0:00 
fname lname 173816 9/26/1997 0:00 
fname lname 178063 1/16/1980 0:00 * 
fname lname 178063 3/3/1976 0:00 x 
fname lname 180725 7/1/2007 0:00 * 
fname lname 180725 1/14/1992 0:00 x 
fname lname 181153 5/1/2001 0:00 

回答

2

难道这行:

.OrderByDescending (m => m.Max (x => x.date)) 

被排序通过他们的最大日期是什么,而不是在每个组中的项目?

这种精简的代码段似乎产生你正在寻找(虽然你不得不用你的文件处理解决它,很明显)

 List<Customer> Customers = new List<Customer>() { 
      new Customer(){ RecordId = 12, Birthday = new DateTime(1970, 1, 1)}, 
      new Customer(){ RecordId = 12, Birthday = new DateTime(1982, 3, 22)}, 
      new Customer(){ RecordId = 12, Birthday = new DateTime(1990, 1, 1)}, 

      new Customer(){ RecordId = 14, Birthday = new DateTime(1960, 1, 1)}, 
      new Customer(){ RecordId = 14, Birthday = new DateTime(1990, 5, 15)}, 
     }; 

     var groups = Customers.GroupBy(c => c.RecordId); 
     IEnumerable<Customer> itemsFromGroupWithMaxDate = groups.Select(g => g.OrderByDescending(c => c.Birthday).First()); 

     foreach(Customer C in itemsFromGroupWithMaxDate) 
      Console.WriteLine(String.Format("{0} {1}", C.RecordId, C.Birthday)); 

或者更好的结果:

IEnumerable<Customer> itemsFromGroupWithMaxDate = Customers.GroupBy(c => c.RecordId).Select(g => g.OrderByDescending(c => c.Birthday).First()); 

以你的代码盲刺,我认为这可能工作:

var recipients = File.ReadAllLines(path) 
    .Select (record => record.Split('|')) 
    .Select (tokens => new 
     { 
     FirstName = tokens[2], 
     LastName = tokens[4], 
     recordId = Convert.ToInt32(tokens[13]), 
     date = Convert.ToDateTime(tokens[17]) 
     } 
    ) 
    .GroupBy (m => m.recordId) 
    .Select(m => OrderByDescending(x => x.date).First()) 
    .OrderBy (m => m.recordId) 

    .Dump(); 
+0

是的,就是这样。该行使用每个组的最大日期对组进行排序。那么,现在我该如何解决它? – DenaliHardtail 2011-03-16 15:07:14

+0

到目前为止,在有限的测试中,您的“盲刺”正在产生预期值。非常感谢你! – DenaliHardtail 2011-03-16 15:17:58

+0

非常欢迎 - 很高兴它工作 – 2011-03-16 15:19:31

5

你orderin g按每组内的最大日期排列整个组。您需要做的是在每个组内订购,以便只选择具有最大日期的项目。

var recipients = File.ReadAllLines(path) 
        .Select(record => record.Split('|')) 
        .Select(tokens => new 
         { 
          FirstName = tokens[2], 
          LastName = tokens[4], 
          recordId = Convert.ToInt32(tokens[13]), 
          date = Convert.ToDateTime(tokens[17]) 
         }) 
        .GroupBy(m => m.recordId, 
           (k, g) => g.OrderByDescending(m => m.date).First()) 
        .OrderBy(m => m.recordId); 

如果性能是很重要的,每个组可能包含很多项目,那么你可能看到略有好转,如果你使用Aggregate以确定该组中的最高记录,而不是OrderByDescending/First组合:

// ... 
.GroupBy(m => m.recordId, 
     (k, g) => g.Aggregate((a, m) => (m.date > a.date) ? m : a)) 
// ... 
+0

哇 - 我不知道GroupBy有一个负责结果选择器,在整个组上运行。尼斯 – 2011-03-16 15:14:33

+0

聚合编辑更酷。感谢今天教给我两件事+1 – 2011-03-16 15:16:38

+0

我尝试了这里提供的三个建议(LukeH's和Adam Rackis's)。所有性能都相同,对于包含10,000条记录的示例文件,执行时间为6.5秒。 @LukeH,谢谢你的建议。我需要深入研究,以充分了解发生了什么。 – DenaliHardtail 2011-03-16 15:27:58

相关问题