2011-03-16 63 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

相關問題