Linq从特定日期获取所有数据,如果数据+ 1天是另一个数据,依此类推

时间:2014-09-19 11:19:56

标签: c# linq

让我们说我有一张叫做任务的桌子。我得到了一个约会,我将从那个日期开始完成所有任务。 但是我也希望那些有限的任务和#34;到第二天,第二天等等。 例如,如果我想要今天的任务,我将通过一个简单的linq查询得到它:

var tasks = db.Tasks.Where(x => x.Date >= DateTime.Today);

但是,如果前一天有任务我也想要那个,以及那天之前的那个等等。 但如果两个任务之间有一天不是任务日,我不想要以下任务。

例如任务日期:09 / 20,09 / 19,09 / 18,09 / 17,19 / 16,09 / 14,19 / 13。在这个例子中,我希望所有任务都在09/16。

如何在linq中完成?

4 个答案:

答案 0 :(得分:1)

首先,让我们定义两个自定义LINQ运算符PairUnpair

  • PairT的序列转换为TTuple<T,T>)对的序列。每对包含原始序列中的两个相邻T

    static IEnumerable<Tuple<T, T>> Pair<T>(this IEnumerable<T> xs)
    {
        if (xs.Any())
        {
            T last = xs.First();
            foreach (T current in xs.Skip(1))
            {
                yield return Tuple.Create(last, current);
                last = current;
            }
        }
    }
    
  • Unpair&#34;变平&#34;这样一对序列回到原始序列中:

    static IEnumerable<T> Unpair<T>(this IEnumerable<Tuple<T, T>> xs)
    {
        if (xs.Any())
        {
            yield return xs.First().Item1;
            foreach (var x in xs)
            {
                yield return x.Item2;
            }
        }
    }
    

使用这两个运算符,您现在可以将查询表达为:

db.Tasks.Where(task => task.Date <= DateTime.Today)
        .OrderByDescending(task => task.Date)
     // .ToArray() // you might need this if `db.Tasks` queries a database 
        .Pair()
        .TakeWhile(pair => pair.Item1.Date - pair.Item2.Date <= TimeSpan.FromDays(1))
        .Unpair()

对于仅使用内置LINQ运算符的解决方案,请参阅my other answer

答案 1 :(得分:1)

就像我在my other answer结束时所承诺的那样,这是一个仅使用内置LINQ运算符的解决方案。

鉴于以下两个定义:

var today = DateTime.Today;
var oneDay = TimeSpan.FromDays(1);

// in-memory cache of all tasks in reverse chronological order (starting from today): 
Task[] tasks = db.Tasks.Where(task => task.Date <= today)
                       .OrderByDescending(task => task.Date)
                       .ToArray(); // see note below for reasons why this is necessary

您可以按如下方式编写查询:

tasks.TakeWhile((task, i) => (i < 1 ? today : tasks[i-1].Date) - task.Date <= oneDay)

  

旁注:为什么需要.ToArray()首先,因为传递给TakeWhile的lambda函数要求Task序列是随机的-无障碍。其次,因为您的ORM / DB提供程序(db)可能不知道如何处理this overload of TakeWhile.ToArray强制执行查询直到该点,结果缓存在 - 记忆。从那时起,它的所有LINQ to Objects都可以处理TakeWhile的变体。但是,this caching might lead to performance problems如果当天之前有很多Task个对象。

答案 2 :(得分:0)

我不认为你可以在linq做类似的事情。 你需要循环

编辑:

列出任务tempTask = new List Tasks();

        for (int i = 0; i < 365; i++)
        {
            var tasks = db.Tasks.Where(x => x.Date.ToString("d") == DateTime.Now.AddDays(-i).ToString("d")).ToList();
            if (tasks.Count != 0)
            {
                tempTask.AddRange(tasks);
            }
            else
            {
                break;
            }
        }

答案 3 :(得分:0)

这是一些未经测试的代码,使用递归:

var allTasks = new List<Task>();
RecureseGetTasks(allTasks, DateTime.Now, db);

//presuming your db is DbContext and .Tasks is List<Task>
//just change class names
void RecurseGetTasks(List<Task> allTasks, DateTime dt, DbContext db){
    var tasks = db.Tasks.Where(t=>t.Date.ToString("yyyy-MM-dd") == dt.ToString("yyyy-MM-dd"));
    if (tasks.Count > 0) {
        allTasks.AddRange(tasks.ToList());
        RecurseGetTasks(allTasks, dt.AddDays(-1), db);
    }
}