可以使用 DateTime 列表过滤 List<object> 的 Linq 查询

Posted

技术标签:

【中文标题】可以使用 DateTime 列表过滤 List<object> 的 Linq 查询【英文标题】:Linq query that can use a list of DateTime to filter a List<object> 【发布时间】:2021-05-02 20:46:26 【问题描述】:

我正在尝试使用动态创建的 DateTimes 列表在任何周末过滤一组数据。 DateTimes 的列表中有几个日期,其中包含一个开始日期和一个到日期。这可以是过去的任何一个周末。

DateTimes 列表看起来类似于:

public class ShiftTimeFilter

     public DateTime ShiftTimeFrom  get; set; 
     public DateTime ShiftTimeTo  get; set; 

创建的日期在new List&lt;ShiftTimeFilter&gt;(); 这将为给定的周末创建以下示例日期。

[0] ShiftTimeFrom : 23/01/2021 00:30, ShiftTimeTo : 23/01/2021 16:30
[1] ShiftTimeFrom : 24/01/2021 17:30, ShiftTimeTo : 24/01/2021 19:30

我可以做一天,即周六或周日,但我不明白如何使用 DateTimes 列表来合并这两天并一次过滤。 myData 模型如下:

public class myData

    public DateTime ReadingDate  get; set; 
    public double ReadingValue  get; set; 

我正在使用的查询:

   var data = myData.Where(x => x.ReadingDate.DayOfWeek == DayOfWeek.Saturday 
                 && x.ReadingDate > ShiftTimeFrom 
                 && x.ReadingDate <= ShiftTimeFrom )
               .Select(x => new Data  myDate = x.ReadingDate, myVal = x.ReadingValue )
               .ToList();

我遇到的一个问题是,客户可能会选择几个月的时间段,而他们会希望每个周末都去看看这段时间。因此,日期列表在某些情况下可以包含 10 或 20 个日期。

我希望使用 Linq 来过滤日期,告诉我所有日期之间的所有数据 List&lt;ShiftTimeFilter&gt;; 以及不在这些日期之间的任何数据,我想将它的值设置为零。

TIA

【问题讨论】:

您可能希望动态生成一个包含一堆“OR”表达式的表达式,就像我描述的here 一样,或者简单地为每个日期范围创建一个单独的查询并将它们合并为我在这个非常相似的问题中进行了描述:***.com/a/45556481/120955 您使用的是哪种 LINQ:LINQ to Objects、SQL、EF 6.x、EF Core 2.0 / 2.1 / 3.x / 5.x?如果有数据库,哪个数据库提供者? 【参考方案1】:

我会在过滤器中添加一些逻辑来简化查询。例如定义一个接口IDateTimeFilter:

public interface IDateTimeFilter 

    bool IsMatch(DateTime pointInTime);


并调整 ShiftTimeFilter 类来实现它:

public class ShiftTimeFilter : IDateTimeFilter 

    public ShiftTimeFilter(DateTime from, DateTime to) 
        if (from < to) 
            ShiftTimeFrom = from;
            ShiftTimeTo = to;
         else 
            ShiftTimeTo = from;
            ShiftTimeFrom = to;
        
    

    public DateTime ShiftTimeFrom  get; 

    public DateTime ShiftTimeTo  get; 

    public Boolean IsMatch(DateTime pointInTime) 
        return (pointInTime >= ShiftTimeFrom) && (pointInTime < ShiftTimeTo);
    


并创建一个组合过滤器的新类,同时实现接口:

public class ShiftTimeFilterList : IDateTimeFilter 

    private IDateTimeFilter[] Filters  get; 

    public ShiftTimeFilterList(IEnumerable<IDateTimeFilter> dateTimeFilters) 
        if (dateTimeFilters is null) throw new ArgumentNullException(nameof(dateTimeFilters));
        Filters = dateTimeFilters.Where(e => e is object).ToArray();
    

    // [Edited: NetMage's simplification implemented]
    public bool IsMatch(DateTime pointInTime) => Filters.Any(filter => filter.IsMatch(pointInTime));


现在您可以使用这样的简单查询来获取匹配数据:

IEnumerable<myData> dataToBeFiltered = GetData();
IDateTimeFilter filter = GenerateFilter();

List<myData> result = dataToBeFiltered.Where(e => filter.IsMatch(e.ReadingDate)).ToList();

【讨论】:

public bool IsMatch(DateTime pointInTime) =&gt; Filters.Any(filter =&gt; filter.IsMatch(pointInTime)); Where(e =&gt; e is object) 的意义何在?你知道eIDateTimeFilter 所以它必须object @NetMage:查询!= null 的半现代方式。 C# 的问题是 != null== null 比较仍然由任何相应的运算符重载处理,然后可以确定给定对象对它们来说足够空并且等于 null 并返回 true 即使非空-reference 被传入(反之亦然)。可以肯定的是,总是可以使用Object.ReferenceEquals,但这有点笨拙。现在is objectis not null 取代(当然很多程序员还不能使用最新的C# 版本,为什么我使用的是旧语法)。 有趣 - 我认为不需要测试。

以上是关于可以使用 DateTime 列表过滤 List<object> 的 Linq 查询的主要内容,如果未能解决你的问题,请参考以下文章

创建一个接受日期时间列表作为参数的存储过程

创建一个 int 和 DateTime 列表

Python中list总结

python列表基本操作

数据类型之列表介绍

Python:用另一个列表过滤列表列表