你忘了提到如果你的某个ID的项目是第一个或最后一个,应该填什么,这种情况下你没有前一个或下一个项目。
如果没有带有someId的项目,你想要什么?一个空序列还是一个带有三个NULL值的序列?
此外,你的日期值唯一吗?如果你有几个日期相同的项目,你想要哪一个作为前一个和下一个项目?
暂且不考虑这些问题,看着你的问题,从你的RepoElements源序列中,你想要选择一个包含3个RepoElements的序列,其中
- result1 = 从源序列中具有Id = someId的元素。这是您的序列的中间元素。
- result[0] = 源序列中日期小于 result1.Date 的元素。
- result[2] = 从源序列中具有 Data > result1.Date 的最小元素
从您的仓库序列中,使用 Where 选择结果
1。然后使用 Select 和 Min、Max 找到 result[0] 和 result[2] 并将所有三个结果放入数组中。最后使用 SingleOrDefault 选择具有正确结果
1的唯一元素:
var result = repo
.Where(repoElement => repoElement.Id == someId)
.Select( result1 => new RepoElement[]
{
// [0]: the largest element with date < date of item with Id == someId
repo.Where(repoElement => repoElement.Date < result1.Date)
.Max(repoElement => repoElement.Date),
// [1] the item with Id == someId
result1,
// [2] the smallest element date > date of item with Id == someId
repo.Where(repoElement => repoElement.Date > result1.Date)
.Min(repoElement => repoElement.Date),
})
.SingleOrDefault();
第一个Where使用索引快速完成。Select需要两次遍历:一次查找小于中间元素的最大元素,一次查找大于中间元素的最小元素。但我认为在大多数情况下,这将比排序更快。
请注意,如果没有具有较小/较大日期的元素,则Max的结果将是默认值,在您的情况下为NULL。
如果您的日期不唯一,则会找到没有日期的最大/最小值。
补充
我刚意识到我使用的Max函数不返回具有最大值的元素,而是返回最大值本身。幸运的是,MSDN Enumerable.Max描述了Max函数使用IComparable。
考虑让您的类实现IComparable,按日期排名。
private class RepoElement: IComparable<MyData>
{
public int Id {get; set;}
public string Name {get; set;}
public DateTime Date {get; set;}
public int CompareTo(RepoElement other)
{
return this.Date.CompareTo(other.Date);
}
}
var result = repo
.Where(repoElement => repoElement.Id == someId)
.Select( result1 => new RepoElement[]
{
repo.Where(repoElement => repoElement.Date < result1.Date).Max(),
repoElement,
repo.Where(repoElement => repoElement.Date > result1.Date).Min(),
}
这将使用扩展函数Enumerable.Max(),它返回一个TSource。
虽然这个方法可以工作,但它的缺点是它只适用于IEnumerable,而不适用于IQueryable。它无法在数据库端执行。
如果您的集合非常大,并且您确实需要将其作为IQueryable(在数据库端)执行,请考虑使用Enumerable.Aggregate查找元素[0]和[2]。
Aggregate比较序列的前两个元素,决定哪一个是“最佳”的,并使用此“最佳”元素与第三个项目进行比较,以再次决定哪一个是“最佳”,并使用此元素与第四个项目进行比较,依此类推。最后返回“最佳”。
var result = repo
.Where(repoElement => repoElement.Id == someId)
.Select(repoElement => new RepoElement[]
{
repo.Where(element => element.Date < repoElement.Date)
.Aggregate(
(largest, next) => next.Date > largest.Date ? next : largest),
repoElement,
repo.Where(element => element.Date > repoElement.Date)
.Aggregate(
(smallest, next) => next.Date < smallest.Date ? next : smallest),
})
.SingleOrDefault();