【问题标题】:Linq continuous date takewhileLinq 连续日期拍摄
【发布时间】:2010-12-10 21:50:10
【问题描述】:

主要问题:我如何按日期对元素进行分组,只有当它们连续且匹配某些属性时?

详情

鉴于这种类型的对象:

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

【问题讨论】:

    标签: c# linq lambda group-by linq-to-objects


    【解决方案1】:

    您也许可以使用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
        }
    }
    

    【讨论】:

    • 不错,但是我怎样才能为分组添加其他条件呢?
    • 取决于你的意思。更复杂的键 -> 使用结构。更复杂的比较 -> 将 DateTime lastDate 更改为 MyObj lastObj,以便您可以与其他属性进行比较。
    • 很抱歉,我无法真正理解它应该如何工作。假设我想将所有元素与后续日期进行分组,但也要使用相同的 ConditionalValue1。我该怎么做?
    • 好的,已修复,谢谢!顺便说一下,巧妙地使用匿名方法和闭包。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-05-29
    • 2015-11-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多