2009-10-28 96 views
0

主要问题:如何将元素按日期分组,只有当它们连续且仅当它们匹配某些属性时才如此?Linq连续日期需要

详细

鉴于这种类型的对象:

public class MyObj 
{ 
    public DateTime Date { get; set; } 
    public string ConditionalValue1 { get; set; } 
    public int ConditionalValue2 { get; set; } 
    public int OtherValue { get; set; } 

    //for test purposes only, i would like to avoid doing this 
    public bool CompareFields(MyObj toBeCompared) 
    { 
     return ConditionalValue1 == toBeCompared.ConditionalValue1 && 
       ConditionalValue2 == toBeCompared.ConditionalValue2; 
    } 
} 

我有他们的名单,填充如下:

//list is ordered for semplicity, but it won't be by default 
//list is a result of a group by too 
var myList = new[] 
{ 
    new MyObj { Date = new DateTime(2009, 10, 20), ConditionalValue1 = "A", ConditionalValue2 = 1, OtherValue = 1 }, 
    new MyObj { Date = new DateTime(2009, 10, 21), ConditionalValue1 = "A", ConditionalValue2 = 1, OtherValue = 2 }, 
    new MyObj { Date = new DateTime(2009, 10, 22), ConditionalValue1 = "B", ConditionalValue2 = 1, OtherValue = 3 }, 
    new MyObj { Date = new DateTime(2009, 10, 23), ConditionalValue1 = "A", ConditionalValue2 = 2, OtherValue = 4 }, 
    new MyObj { Date = new DateTime(2009, 10, 24), ConditionalValue1 = "A", ConditionalValue2 = 2, OtherValue = 5 }, 
    new MyObj { Date = new DateTime(2009, 10, 25), ConditionalValue1 = "A", ConditionalValue2 = 1, OtherValue = 6 }, 
    //Note the hole for day 26 
    new MyObj { Date = new DateTime(2009, 10, 27), ConditionalValue1 = "A", ConditionalValue2 = 1, OtherValue = 7}, 
}; 

通缉(伪):

List = 
    { ListOfObjects }, //First has date = "2009/10/20", last has = "2009/10/21" 
    { ListOfObjects }, //First has date = "2009/10/22", last has = "2009/10/22" //reason: doesn't match Value1 
    { ListOfObjects }, //First has date = "2009/10/23", last has = "2009/10/24" 
    { ListOfObjects }, //First has date = "2009/10/25", last has = "2009/10/25" //reason: doesn't match Value2 
    { ListOfObjects } //First has date = "2009/10/27", last has = "2009/10/27" //reason: there is no "2009/10/26" object 

测试至今

//i pick the first element, to be compared with the next ones 
var firstInList = myList.First(); 
//take while date is consequent and fields are compared 
var partialList = myList 
    .TakeWhile(
     (obj, index) => obj.Date == firstInList.Date.AddDays(index) && 
         obj.CompareFields(firstInList) 
    ); 

这部分的工作,当然它会返回正确的结果只有第一个匹配的元素。

我可以Skip(count)列表,直到0的元素,但我想用group by,使用IEqualityComparer替代方法CompareFields

回答

2

您可能已经使用Enumerable.GroupBy。不过,我有一种感觉,它可能会循环整个集合。如果是这样,您可以随时创建自己的SequencedGroupBy扩展方法。

警告:不会与并行扩展(进行AsParallel)

DateTime lastGroupDate = DateTime.MinValue; 
DateTime lastDate = DateTime.MinValue; 

IEnumerable<IGrouping<DateTime, MyObj>> groups = myList 
    .GroupBy(o => 
     { 
      if (lastGroupDate != DateTime.MinValue && 
       o.Date.AddDays(-1) == lastDate) 
      { 
       lastDate = o.Date; 
      } 
      else 
      { 
       lastGroupDate = o.Date; 
       lastDate = o.Date; 
      } 

      return lastGroupDate; 
     } 
    ); 

foreach(IGrouping<DateTime, MyObj> grouping in groups) 
{ 
    // grouping.Key == the grouped date/first in sequence 

    foreach(MyObj obj in grouping) 
    { 
     // obj.Date == actual date 
    } 
} 
+0

一个不错的工作,但我怎么可以添加其他条件太分组? – 2009-10-28 16:03:04

+0

取决于你的意思。更复杂的关键 - >使用一个结构。更复杂的比较 - >将DateTime lastDate更改为MyObj lastObj,以便与其他属性进行比较。 – 2009-10-28 16:29:17

+0

对不起,我不能真正理解它应该如何工作。假设我想将所有元素与后续日期进行分组,但同时也是SAME Con​​ditionalValue1。我该怎么做? – 2009-10-28 16:33:38