Linq 连续日期 takewhile
主要问题:如何按日期对元素进行分组,只有在连续且匹配某些属性的情况下?
详细信息:
给定这种类型的对象:
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
而不是方法比较字段
。
Main problem: how do i group elements by their Date, only if continuous and only if they match some properties?
Details:
Given this type of object:
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;
}
}
I have a list of them, populated as follow:
//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},
};
Wanted (pseudocode):
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
Tests so far:
//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)
);
This is partially working, as of course it will return the correct results only for the first matching elements.
I could Skip(count)
the list until 0 elements, but I would like to use group by
, using an IEqualityComparer
instead of method CompareFields
.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
您也许可以使用Enumerable.GroupBy。然而,我有一种感觉,它可能会贯穿整个系列。如果是这样,您始终可以创建自己的 SequencedGroupBy 扩展方法。
警告:不适用于并行扩展 (AsParallel)
You may be able to use Enumerable.GroupBy. However, I have a feeling it might loop through the entire set. If so, you could always create your own SequencedGroupBy extension method.
Warning: won't work with parallel extensions (AsParallel)