有可枚举的扩展方法
Take<TSource>(
IEnumerable<TSource> source,
int count
)
从头开始接受第一个count
元素。
有没有办法从最后获取元素? 或者更好的方法是将元素从偏移量带到最后?
由于
答案 0 :(得分:13)
finiteList.Reverse().Take(count).Reverse();
或
finiteList.Skip(finiteList.Count() - count)
这样做有一些开销,所以自定义方法会更好。
更新:自定义方法
public static class EnumerableExtensions
{
public static IEnumerable<T> TakeLast<T>(this IEnumerable<T> source, int count)
{
if (source == null) throw new ArgumentNullException("source");
if (count < 0) throw new ArgumentOutOfRangeException("count");
if (count == 0) yield break;
var queue = new Queue<T>(count);
foreach (var t in source)
{
if (queue.Count == count) queue.Dequeue();
queue.Enqueue(t);
}
foreach (var t in queue)
yield return t;
}
}
更新:根据dtb的答案更改了代码: - )
对熊的评论:请看这个例子:
var lastFive = Enumerable.Range(1, 10).TakeLast(5);
var lastFive2 = Enumerable.Range(1, 10).TakeLast2(5); //Bear´s way
Queue<int> q = (Queue<int>)lastFive2;
q.Dequeue();
//Is lastFive2 still last five? no...
您可能会更改lastFive2
的值,因此该方法可能不安全或至少不是功能方式。
承担:
我对安全的意义是:
var lastFive2 = Enumerable.Range(1, 10).TakeLast2(5); //Bear´s way
//some = Some method which you don't control - it could be from another assembly which represents a crazy plugin etc.
some(lastFive2);
//Now what?
在这些情况下,您必须制作副本才能确定。但在大多数情况下,你的方式会很好 - 比这更有效,所以+1:)
一个想法是使用只有内部Enqueue等的队列。
答案 1 :(得分:3)
MoreLINQ提供TakeLast extension method:
var last10 = finiteList.TakeLast(10);
要将元素从偏移量转移到结尾,Enumerable.Skip应该可以解决问题:
var allFromOffsetToEnd = finiteList.Skip(offset);
答案 2 :(得分:2)
@lasseespeholt:
public static class EnumerableExtensions
{
public static ReadOnlyEnumerable<T> AsReadOnly<T>(
this IEnumerable<T> source)
{
return new ReadOnlyEnumerable<T>(source);
}
}
public sealed class ReadOnlyEnumerable<T> : IEnumerable<T>
{
private readonly IEnumerable<T> _source;
public ReadOnlyEnumerable(IEnumerable<T> source)
{
if (_source == null)
{
throw new ArgumentNullException("source");
}
_source = source;
}
public IEnumerator<T> GetEnumerator()
{
return _source.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return _source.GetEnumerator();
}
}
public static IEnumerable<T> TakeLast<T>(this IEnumerable<T> source, int count)
{
if (source == null) throw new ArgumentNullException("source");
if (count < 0) throw new ArgumentOutOfRangeException("count");
if (count == 0)
return Enumerable.Empty<T>();
var queue = new Queue<T>(count);
foreach (var t in source)
{
if (queue.Count == count) queue.Dequeue();
queue.Enqueue(t);
}
return queue.AsReadOnly();
}
答案 3 :(得分:1)
关于表现的说明。这里有很多答案在IEnumerable<>
运行,这可能就是你需要和应该使用的。
但是如果数据集很大并且类型为List<>
或类似,那么您可以使用以下内容阻止大量不必要的迭代:
// demo, no errorhandling
public static IEnumerable<T> TakeFrom<T>(this IList<T> list, int offset)
{
for (int i = offset; i < list.Count; i += 1)
{
yield return list[i];
}
}