如何使用loop或linq比较和分割开始时间和结束时间?

时间:2019-05-15 11:37:27

标签: c# linq

我有一个像这样的列表

[15/05/2019 10:01]
[15/05/2019 10:03]
[15/05/2019 10:05]
[15/05/2019 10:09]
[15/05/2019 10:11]
[15/05/2019 10:19]
[15/05/2019 10:22]
[15/05/2019 10:28]
[15/05/2019 10:30]
[15/05/2019 10:35]
[15/05/2019 10:38]
[15/05/2019 10:42]
[15/05/2019 10:45]
[15/05/2019 10:55]
[15/05/2019 11:01]
[15/05/2019 11:11]
[15/05/2019 11:18]
[15/05/2019 11:25]
[15/05/2019 11:29]
[15/05/2019 11:41]

我还有另一个列表

[StartTime=15/05/2019 10:08,EndTime=15/05/2019 10:28]
[StartTime=15/05/2019 10:42,EndTime=15/05/2019 10:48]
[StartTime=15/05/2019 11:20,EndTime=15/05/2019 11:26]

结果

[StartTime=15/05/2019 10:01,EndTime=15/05/2019 10:05]
[StartTime=15/05/2019 10:30,EndTime=15/05/2019 10:38]
[StartTime=15/05/2019 10:55,EndTime=15/05/2019 11:18]
[StartTime=15/05/2019 11:29,EndTime=15/05/2019 11:41]

如果可以使用LINQ或for循环获取开始时间和结束时间

例如: 1)在第二个列表中选择第一个项目

[StartTime=15/05/2019 10:08,EndTime=15/05/2019 10:28]

并检查第一个列表中需要以下结果的时间

[15/05/2019 10:01]
[15/05/2019 10:03]
[15/05/2019 10:05]

现在将StartTime视为[15/05/2019 10:01],将EndTime视为[15/05/2019 10:05]

2)现在再次被视为第二个列表,然后选择第二个项目

[StartTime=15/05/2019 10:42,EndTime=15/05/2019 10:48]

,然后检查第二个列表的第一结束时间到第二个列表的第二个开始时间的计时,这些计时结果应该是

[15/05/2019 10:30]
[15/05/2019 10:35]
[15/05/2019 10:38]

现在将StartTime视为[15/05/2019 10:30],将EndTime视为[15/05/2019 10:38] ..

类似地,我们遵循以下步骤。

谢谢

2 个答案:

答案 0 :(得分:0)

有了明确的问题和描述,一切都很容易。

1 /。对于您范围内的每个日期,您将选择以下日期:
   -低于开始日期,并且-高于先前的范围日期。
从尽可能低的值(下限)开始。
2 /。订购结果。
3 /。如果您有多个结果,则将第一个和最后一个作为新的日期范围。

代码:

var result = new List<Foo>();
var lastLowerBound = DateTime.MinValue;
foreach (var range in List2)
{
    var filteredDates = List1.Where(d => d >= lastLowerBound && d <= range.StartTime)
                             .OrderBy(x => x);
    if (filteredDates.Count()> 1)
    {
        result.Add(
            new Foo { 
                StartTime = filteredDates.First(), 
                EndTime = filteredDates.Last()
        });
    }
    else
    {
        //How to make a date range if there is only one date?
    }
    lastLowerBound = range.EndTime;
}

您填充的结果范围小于过滤条件范围。 最后一个只剩下一个范围。当数据优于上一个范围时。

此时,您可以在foreach之外重复工作。

var filteredDates = List1.Where(d => d > lastLowerBound)
                        .OrderBy(x => x).First();

if (filteredDates.Count() > 1)
{
    result2.Add(new Foo { StartTime = filteredDates.First(), EndTime = filteredDates.Last() });
}   

public class Foo
{
    public DateTime StartTime { get; set; }
    public DateTime EndTime { get; set; }
}

NB:可以进行很多优化。 它只是基于OP描述的最简单算法。 例如如何将英语翻译为代码。

答案 1 :(得分:0)

通常,我会使用一些扩展方法来简化此过程,但这是标准的LINQ解决方案。假设您的第一个Listsrc,第二个ListrangeBreaks,并且rangeBreaks已正确排序。

然后,您可以通过跳过rangeBreaks本身(跳过第一个)来创建要查找的间隔的新列表,因此可以将其中一个的EndTime与其中的StartTime组合在一起下一个:

var gaps = new[] { new { DateTime.MinValue, MaxValue = rangeBreaks[0].StartTime } }
                .Concat(rangeBreaks.Zip(rangeBreaks.Skip(1), (f, s) => new { MinValue = f.EndTime, MaxValue = s.StartTime }))
                .Concat(new[] { new { MinValue = rangeBreaks.Last().EndTime, DateTime.MaxValue } });

这样,很容易将src List分成适合每个间隙的组,然后使用每个间隙的第一个和最后一个来创建新的间隔记录。

var ans = gaps.Select(g => src.Where(s => g.MinValue < s && s < g.MaxValue).ToList())
              .Select(gl => new { StartTime = gl.Min(), EndTime = gl.Max() });

注意:如果订购了src,则可以使用First()Last()代替Min()Max()