有可枚举的扩展方法
Take<TSource>(
IEnumerable<TSource> source,
int count
)
它从一开始就采用第一个count
元素。
有没有办法从最后获取元素?甚至更好的方法将元素从偏移量带到最后?
谢谢
有可枚举的扩展方法
Take<TSource>(
IEnumerable<TSource> source,
int count
)
它从一开始就采用第一个count
元素。
有没有办法从最后获取元素?甚至更好的方法将元素从偏移量带到最后?
谢谢
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 等的队列。
var last10 = finiteList.TakeLast(10);
要将元素从偏移量带到末尾,Enumerable.Skip应该可以解决问题:
var allFromOffsetToEnd = finiteList.Skip(offset);
@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();
}
关于性能的说明。这里有很多答案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];
}
}