为什么Linq没有头和尾?

Jim*_*ies 8 c# linq tail head

我经常发现自己想在IEnumerables上使用Head和Tail方法,这些方法在Linq中不存在.虽然我可以很容易地写自己的,但我想知道他们是否被故意排除在外.例如,

var finalCondition = new Sql("WHERE @0 = @1", conditions.Head().Key, conditions.Head().Value);
foreach (var condition in conditions.Tail())
{
  finalCondition.Append("AND @0 = @1", condition.Key, condition.Value);
}
Run Code Online (Sandbox Code Playgroud)

那么,Linq的最佳实践是什么?事实上,我一直在寻找这个标志,我没有做推荐的事情吗?如果没有,那么为什么这个常见的功能范例没有在Linq中实现?

nvo*_*igt 16

从技术上讲,你的头是第一个(),你的尾巴是.Skip(1).但也许你可以找到更好的解决方案?就像在IEnumerable上使用.Aggregate()一样?

  • @MatthewWatson是的.头尾故事的事情是你在*t​​ail之前不调用head*,而是分割列表的概念.nvoigt说OP的代码等同于调用first/skip(1),并且它不是使用head/tail的好例子. (3认同)
  • @MatthewWatson不,`tail`不是最后一个元素. (2认同)

Aro*_*ron 8

鉴于界面IEnumerable<T>,不能始终确保性能.

您注意到大多数函数式编程语言都实现了tail和head.但是应该注意,这些语言在内存构造中起作用.

IEnumerable<T> 没有任何这样的约束,因此不能认为这是有效的.

例如,一个常见的功能模式是递归地处理集合的头部,然后递归到调用的尾部......

例如,如果您使用Entity Framework执行此操作,则会将以下(元)调用发送到SQL服务器,紧密循环.

Select * from
(
    Select * from
    (
         Select * from
         (...)
         Skip 1
    )
    Skip 1
);
Run Code Online (Sandbox Code Playgroud)

这将是非常低效的.

编辑:

来考虑一下吧.另一个原因是,C#/ VB.Net不支持尾递归,因此,这种模式很容易造成一个StackOverflow.

  • 这个答案是不正确和不相关的。不应该接受。[`.Skip(1)`](https://msdn.microsoft.com/library/bb358985(v = vs.100).aspx)可以轻松访问`IEnumerable`尾部,并且无论是否具有性能,都不会令人惊讶结构是否在内存中。IEnumerable类被设计为一次移动一个元素,这就是Skip(1)所做的。仅当您需要计算“ IEnumerable”或跳到任意“索引”中的元素时,性能才会出现惊奇。 (2认同)