让我们说我有一张叫做任务的桌子。我得到了一个约会,我将从那个日期开始完成所有任务。 但是我也希望那些有限的任务和#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中完成?
答案 0 :(得分:1)
首先,让我们定义两个自定义LINQ运算符Pair
和Unpair
:
Pair
将T
的序列转换为T
(Tuple<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 ofTakeWhile
:.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);
}
}