string s[s.Length-1] vs s.Last() - c#

Q1) I wonder if calling s.Last() linq extension method is as efficient as doing s[s.Length-1]. I prefer the first option but I don't know if the implementation takes advantage of the current type.
Q2) This could be another interesting question. Does linq extension methods takes advantage of the type when they are used or they just see the object as an IEnumerable?

No, it will not be as efficient as directly indexing, which is O(1). We can see in the reference source for Enumerable.Last:
public static TSource Last<TSource>(this IEnumerable<TSource> source) {
if (source == null) throw Error.ArgumentNull("source");
IList<TSource> list = source as IList<TSource>;
if (list != null) {
int count = list.Count;
if (count > 0) return list[count - 1];
}
else {
using (IEnumerator<TSource> e = source.GetEnumerator()) {
if (e.MoveNext()) {
TSource result;
do {
result = e.Current;
} while (e.MoveNext());
return result;
}
}
}
throw Error.NoElements();
}
Since String does not implement IList<char> it will go to the branch that uses the enumerator requiring all characters to be checked until the last one is found (which is O(n)).
As you can see, in some cases, LINQ methods take into account more efficient ways to access data provided by various interfaces. Other examples, include First, Count, and ElementAt.

It is not as efficient, it has a special case if you call it on something that implements an IList but not for string. Here is the implementation from Reflector.
[__DynamicallyInvokable]
public static TSource Last<TSource>(this IEnumerable<TSource> source)
{
if (source == null)
{
throw Error.ArgumentNull("source");
}
IList<TSource> list = source as IList<TSource>;
if (list != null)
{
int count = list.Count;
if (count > 0)
{
return list[count - 1];
}
}
else
{
using (IEnumerator<TSource> enumerator = source.GetEnumerator())
{
if (enumerator.MoveNext())
{
TSource current;
do
{
current = enumerator.Current;
}
while (enumerator.MoveNext());
return current;
}
}
}
throw Error.NoElements();
}
You can see that it enumerates through the whole sequence and then just returns the last element.

If you're so concerned about performance of string.Last() then you can get the best of both worlds by implementing your own overload of Last(). If your overload is a better match then Enumerable.Last() then yours will be used.
internal class Program
{
private static void Main()
{
Console.WriteLine("Hello".Last());
}
}
public static class StringExtensions
{
public static char Last(this string text)
{
if (text == null)
{
throw new ArgumentNullException("text");
}
int length = text.Length;
if (length == 0)
{
throw new ArgumentException("Argument cannot be empty.", "text");
}
return text[length - 1];
}
}
If you want to risk it and take out the argument checks, you can do that too, but I wouldn't.
I tested to confirm StringExtensions.Last() is being called even though I use this technique often enough to know for sure it works. :-)
Note: In order for your overload to be called the variable must be declared as a string so the compiler knows it's a string. If it's an IEnumerable<char> that happens to be a string at runtime, the more efficient method will not be called, example:
private static void Main()
{
IEnumerable<char> s = "Hello";
Console.WriteLine(s.Last());
}
Here StringExtensions.Last() is not called because the compiler doesn't know s is a string, it only knows it's IEnumerable<char> (remember member overload resolution is decided at compile time). For strings this is not much of a concern, but for other optimizations it can be.

Related

Simple NUnit test fail because exception is not thrown ( out of the test is thrown)

I'm creating an extension generic method Apply, what it does is not important, the major problem is that I cant understand how to test it, a simple test like ApplyOnNullFunctionThrow fail to say that no exception is thrown, but if I run a "manual test" from main it throws
The main:
class Program
{
static void Main(string[] args)
{
foreach (var i in first.Apply(second,f)) Console.WriteLine("{0}", i);
Console.ReadLine();
}
}
The extension method:
public static class Applier
{
public static IEnumerable<T> Apply<T>(this IEnumerable<T> first, IEnumerable<T> second,Func<T,T,T> f)
{
if(f == null ) throw new ArgumentNullException();
if (null==first || null==second) throw new ArgumentNullException();
var x=second.GetEnumerator();
foreach (var item in first)
{
yield return x.MoveNext() ? f(item, x.Current) : f(item, default);
}
while (x.MoveNext())
{
yield return f(default, x.Current);
}
}
}
The test:
class ApplierTests
{
[TestCase(new[]{1,2,3},new[]{10,20,30},null)]
public void ApplyOnNullFunctionThrow<T>(IEnumerable<T> first, IEnumerable<T> second,Func<T,T,T> f)
{
Assert.Throws<ArgumentNullException>(() => first.Apply(second, f));
}
}
In your Apply method you have yield keyword which means that the elements of the sequence will be returned one at a time. So when you just call the method with yield keyword, under the hood it does nothing, but just returns an iterator (IEnumerable<T>) which you can use in, for example, foreach. The bottom line here is that the code of your original Apply method isn't executed until MoveNext is called on the iterator returned, therefore it doesn't throw the exception. To fix this you may want to have a wrapper which is without yield keyword:
public static IEnumerable<T> Apply<T>(this IEnumerable<T> first, IEnumerable<T> second,Func<T,T,T> f)
{
if(f == null ) throw new ArgumentNullException();
if (null==first || null==second) throw new ArgumentNullException();
return ApplyInternal(first, second, f);
}
private static IEnumerable<T> ApplyInternal<T>(...) {
var x=second.GetEnumerator();
foreach (var item in first)
{
yield return x.MoveNext() ? f(item, x.Current) : f(item, default);
}
while (x.MoveNext())
{
yield return f(default, x.Current);
}
}
Instead of creating a private method you also can use C# 7 feature called local functions as alternative
See also, the exception is thrown when you call the method in Main, because you use the result of the method in the foreach statement which is compiled into repeated calls to MoveNext.

Calling method with IEnumerable<T> sequence as argument, if that sequence is not empty

I have method Foo, which do some CPU intensive computations and returns IEnumerable<T> sequence. I need to check, if that sequence is empty. And if not, call method Bar with that sequence as argument.
I thought about three approaches...
Check, if sequence is empty with Any(). This is ok, if sequence is really empty, which will be case most of the times. But it will have horrible performance, if sequence will contains some elements and Foo will need them compute again...
Convert sequence to list, check if that list it empty... and pass it to Bar. This have also limitation. Bar will need only first x items, so Foo will be doing unnecessary work...
Check, if sequence is empty without actually reset the sequence. This sounds like win-win, but I can't find any easy build-in way, how to do it. So I create this obscure workaround and wondering, whether this is really a best approach.
Condition
var source = Foo();
if (!IsEmpty(ref source))
Bar(source);
with IsEmpty implemented as
bool IsEmpty<T>(ref IEnumerable<T> source)
{
var enumerator = source.GetEnumerator();
if (enumerator.MoveNext())
{
source = CreateIEnumerable(enumerator);
return false;
}
return true;
IEnumerable<T> CreateIEnumerable(IEnumerator<T> usedEnumerator)
{
yield return usedEnumerator.Current;
while (usedEnumerator.MoveNext())
{
yield return usedEnumerator.Current;
}
}
}
Also note, that calling Bar with empty sequence is not option...
EDIT:
After some consideration, best answer for my case is from Olivier Jacot-Descombes - avoid that scenario completely. Accepted solution answers this question - if it is really no other way.
I don't know whether your algorithm in Foo allows to determine if the enumeration will be empty without doing the calculations. But if this is the case, return null if the sequence would be empty:
public IEnumerable<T> Foo()
{
if (<check if sequence will be empty>) {
return null;
}
return GetSequence();
}
private IEnumerable<T> GetSequence()
{
...
yield return item;
...
}
Note that if a method uses yield return, it cannot use a simple return to return null. Therefore a second method is needed.
var sequence = Foo();
if (sequence != null) {
Bar(sequence);
}
After reading one of your comments
Foo need to initialize some resources, parse XML file and fill some HashSets, which will be used to filter (yield) returned data.
I suggest another approach. The time consuming part seems to be the initialization. To be able to separate it from the iteration, create a foo calculator class. Something like:
public class FooCalculator<T>
{
private bool _isInitialized;
private string _file;
public FooCalculator(string file)
{
_file = file;
}
private EnsureInitialized()
{
if (_isInitialized) return;
// Parse XML.
// Fill some HashSets.
_isInitialized = true;
}
public IEnumerable<T> Result
{
get {
EnsureInitialized();
...
yield return ...;
...
}
}
}
This ensures that the costly initialization stuff is executed only once. Now you can safely use Any().
Other optimizations are conceivable. The Result property could remember the position of the first returned element, so that if it is called again, it could skip to it immediately.
You would like to call some function Bar<T>(IEnumerable<T> source) if and only if the enumerable source contains at least one element, but you're running into two problems:
There is no method T Peek() in IEnumerable<T> so you would need to actually begin to evaluate the enumerable to see if it's nonempty, but...
You don't want to even partially double-evaluate the enumerable since setting up the enumerable might be expensive.
In that case your approach looks reasonable. You do, however, have some issues with your imlementation:
You need to dispose enumerator after using it.
As pointed out by Ivan Stoev in comments, if the Bar() method attempts to evaluate the IEnumerable<T> more than once (e.g. by calling Any() then foreach (...)) then the results will be undefined because usedEnumerator will have been exhausted by the first enumeration.
To resolve these issues, I'd suggest modifying your API a little and create an extension method IfNonEmpty<T>(this IEnumerable<T> source, Action<IEnumerable<T>> func) that calls a specified method only if the sequence is nonempty, as shown below:
public static partial class EnumerableExtensions
{
public static bool IfNonEmpty<T>(this IEnumerable<T> source, Action<IEnumerable<T>> func)
{
if (source == null|| func == null)
throw new ArgumentNullException();
using (var enumerator = source.GetEnumerator())
{
if (!enumerator.MoveNext())
return false;
func(new UsedEnumerator<T>(enumerator));
return true;
}
}
class UsedEnumerator<T> : IEnumerable<T>
{
IEnumerator<T> usedEnumerator;
public UsedEnumerator(IEnumerator<T> usedEnumerator)
{
if (usedEnumerator == null)
throw new ArgumentNullException();
this.usedEnumerator = usedEnumerator;
}
public IEnumerator<T> GetEnumerator()
{
var localEnumerator = System.Threading.Interlocked.Exchange(ref usedEnumerator, null);
if (localEnumerator == null)
// An attempt has been made to enumerate usedEnumerator more than once;
// throw an exception since this is not allowed.
throw new InvalidOperationException();
yield return localEnumerator.Current;
while (localEnumerator.MoveNext())
{
yield return localEnumerator.Current;
}
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
}
Demo fiddle with unit tests here.
If you can change Bar then how about change it to TryBar that returns false when IEnumerable<T> was empty?
bool TryBar(IEnumerable<Foo> source)
{
var count = 0;
foreach (var x in source)
{
count++;
}
return count > 0;
}
If that doesn't work for you could always create your own IEnumerable<T> wrapper that caches values after they have been iterated once.
One improvement for your IsEmpty would be to check if source is ICollection<T>, and if it is, check .Count (also, dispose the enumerator):
bool IsEmpty<T>(ref IEnumerable<T> source)
{
if (source is ICollection<T> collection)
{
return collection.Count == 0;
}
var enumerator = source.GetEnumerator();
if (enumerator.MoveNext())
{
source = CreateIEnumerable(enumerator);
return false;
}
enumerator.Dispose();
return true;
IEnumerable<T> CreateIEnumerable(IEnumerator<T> usedEnumerator)
{
yield return usedEnumerator.Current;
while (usedEnumerator.MoveNext())
{
yield return usedEnumerator.Current;
}
usedEnumerator.Dispose();
}
}
This will work for arrays and lists.
I would, however, rework IsEmpty to return:
IEnumerable<T> NotEmpty<T>(IEnumerable<T> source)
{
if (source is ICollection<T> collection)
{
if (collection.Count == 0)
{
return null;
}
return source;
}
var enumerator = source.GetEnumerator();
if (enumerator.MoveNext())
{
return CreateIEnumerable(enumerator);
}
enumerator.Dispose();
return null;
IEnumerable<T> CreateIEnumerable(IEnumerator<T> usedEnumerator)
{
yield return usedEnumerator.Current;
while (usedEnumerator.MoveNext())
{
yield return usedEnumerator.Current;
}
usedEnumerator.Dispose();
}
}
Now, you would check if it returned null.
The accepted answer is probably the best approach but, based on, and I quote:
Convert sequence to list, check if that list it empty... and pass it to Bar. This have also limitation. Bar will need only first x items, so Foo will be doing unnecessary work...
Another take would be creating an IEnumerable<T> that partially caches the underlying enumeration. Something along the following lines:
interface IDisposableEnumerable<T>
:IEnumerable<T>, IDisposable
{
}
static class PartiallyCachedEnumerable
{
public static IDisposableEnumerable<T> Create<T>(
IEnumerable<T> source,
int cachedCount)
{
if (source == null)
throw new NullReferenceException(
nameof(source));
if (cachedCount < 1)
throw new ArgumentOutOfRangeException(
nameof(cachedCount));
return new partiallyCachedEnumerable<T>(
source, cachedCount);
}
private class partiallyCachedEnumerable<T>
: IDisposableEnumerable<T>
{
private readonly IEnumerator<T> enumerator;
private bool disposed;
private readonly List<T> cache;
private readonly bool hasMoreItems;
public partiallyCachedEnumerable(
IEnumerable<T> source,
int cachedCount)
{
Debug.Assert(source != null);
Debug.Assert(cachedCount > 0);
enumerator = source.GetEnumerator();
cache = new List<T>(cachedCount);
var count = 0;
while (enumerator.MoveNext() &&
count < cachedCount)
{
cache.Add(enumerator.Current);
count += 1;
}
hasMoreItems = !(count < cachedCount);
}
public void Dispose()
{
if (disposed)
return;
enumerator.Dispose();
disposed = true;
}
public IEnumerator<T> GetEnumerator()
{
foreach (var t in cache)
yield return t;
if (disposed)
yield break;
while (enumerator.MoveNext())
{
yield return enumerator.Current;
cache.Add(enumerator.Current)
}
Dispose();
}
IEnumerator IEnumerable.GetEnumerator()
=> GetEnumerator();
}
}

Why does this string extension method not throw an exception?

I've got a C# string extension method that should return an IEnumerable<int> of all the indexes of a substring within a string. It works perfectly for its intended purpose and the expected results are returned (as proven by one of my tests, although not the one below), but another unit test has discovered a problem with it: it can't handle null arguments.
Here's the extension method I'm testing:
public static IEnumerable<int> AllIndexesOf(this string str, string searchText)
{
if (searchText == null)
{
throw new ArgumentNullException("searchText");
}
for (int index = 0; ; index += searchText.Length)
{
index = str.IndexOf(searchText, index);
if (index == -1)
break;
yield return index;
}
}
Here is the test that flagged up the problem:
[TestMethod]
[ExpectedException(typeof(ArgumentNullException))]
public void Extensions_AllIndexesOf_HandlesNullArguments()
{
string test = "a.b.c.d.e";
test.AllIndexesOf(null);
}
When the test runs against my extension method, it fails, with the standard error message that the method "did not throw an exception".
This is confusing: I have clearly passed null into the function, yet for some reason the comparison null == null is returning false. Therefore, no exception is thrown and the code continues.
I have confirmed this is not a bug with the test: when running the method in my main project with a call to Console.WriteLine in the null-comparison if block, nothing is shown on the console and no exception is caught by any catch block I add. Furthermore, using string.IsNullOrEmpty instead of == null has the same problem.
Why does this supposedly-simple comparison fail?
You are using yield return. When doing so, the compiler will rewrite your method into a function that returns a generated class that implements a state machine.
Broadly speaking, it rewrites locals to fields of that class and each part of your algorithm between the yield return instructions becomes a state. You can check with a decompiler what this method becomes after compilation (make sure to turn off smart decompilation which would produce yield return).
But the bottom line is: the code of your method won't be executed until you start iterating.
The usual way to check for preconditions is to split your method in two:
public static IEnumerable<int> AllIndexesOf(this string str, string searchText)
{
if (str == null)
throw new ArgumentNullException("str");
if (searchText == null)
throw new ArgumentNullException("searchText");
return AllIndexesOfCore(str, searchText);
}
private static IEnumerable<int> AllIndexesOfCore(string str, string searchText)
{
for (int index = 0; ; index += searchText.Length)
{
index = str.IndexOf(searchText, index);
if (index == -1)
break;
yield return index;
}
}
This works because the first method will behave just like you expect (immediate execution), and will return the state machine implemented by the second method.
Note that you should also check the str parameter for null, because extensions methods can be called on null values, as they're just syntactic sugar.
If you're curious about what the compiler does to your code, here's your method, decompiled with dotPeek using the Show Compiler-generated Code option.
public static IEnumerable<int> AllIndexesOf(this string str, string searchText)
{
Test.<AllIndexesOf>d__0 allIndexesOfD0 = new Test.<AllIndexesOf>d__0(-2);
allIndexesOfD0.<>3__str = str;
allIndexesOfD0.<>3__searchText = searchText;
return (IEnumerable<int>) allIndexesOfD0;
}
[CompilerGenerated]
private sealed class <AllIndexesOf>d__0 : IEnumerable<int>, IEnumerable, IEnumerator<int>, IEnumerator, IDisposable
{
private int <>2__current;
private int <>1__state;
private int <>l__initialThreadId;
public string str;
public string <>3__str;
public string searchText;
public string <>3__searchText;
public int <index>5__1;
int IEnumerator<int>.Current
{
[DebuggerHidden] get
{
return this.<>2__current;
}
}
object IEnumerator.Current
{
[DebuggerHidden] get
{
return (object) this.<>2__current;
}
}
[DebuggerHidden]
public <AllIndexesOf>d__0(int <>1__state)
{
base..ctor();
this.<>1__state = param0;
this.<>l__initialThreadId = Environment.CurrentManagedThreadId;
}
[DebuggerHidden]
IEnumerator<int> IEnumerable<int>.GetEnumerator()
{
Test.<AllIndexesOf>d__0 allIndexesOfD0;
if (Environment.CurrentManagedThreadId == this.<>l__initialThreadId && this.<>1__state == -2)
{
this.<>1__state = 0;
allIndexesOfD0 = this;
}
else
allIndexesOfD0 = new Test.<AllIndexesOf>d__0(0);
allIndexesOfD0.str = this.<>3__str;
allIndexesOfD0.searchText = this.<>3__searchText;
return (IEnumerator<int>) allIndexesOfD0;
}
[DebuggerHidden]
IEnumerator IEnumerable.GetEnumerator()
{
return (IEnumerator) this.System.Collections.Generic.IEnumerable<System.Int32>.GetEnumerator();
}
bool IEnumerator.MoveNext()
{
switch (this.<>1__state)
{
case 0:
this.<>1__state = -1;
if (this.searchText == null)
throw new ArgumentNullException("searchText");
this.<index>5__1 = 0;
break;
case 1:
this.<>1__state = -1;
this.<index>5__1 += this.searchText.Length;
break;
default:
return false;
}
this.<index>5__1 = this.str.IndexOf(this.searchText, this.<index>5__1);
if (this.<index>5__1 != -1)
{
this.<>2__current = this.<index>5__1;
this.<>1__state = 1;
return true;
}
goto default;
}
[DebuggerHidden]
void IEnumerator.Reset()
{
throw new NotSupportedException();
}
void IDisposable.Dispose()
{
}
}
This is invalid C# code, because the compiler is allowed to do things the language doesn't allow, but which are legal in IL - for instance naming the variables in a way you couldn't to avoid name collisions.
But as you can see, the AllIndexesOf only constructs and returns an object, whose constructor only initializes some state. GetEnumerator only copies the object. The real work is done when you start enumerating (by calling the MoveNext method).
You have an iterator block. None of the code in that method is ever run outside of calls to MoveNext on the returned iterator. Calling the method does noting but create the state machine, and that won't ever fail (outside of extremes such as out of memory errors, stack overflows, or thread abort exceptions).
When you actually attempt to iterate the sequence you'll get the exceptions.
This is why the LINQ methods actually need two methods to have the error handling semantics they desire. They have a private method that is an iterator block, and then a non-iterator block method that does nothing but do the argument validation (so that it can be done eagerly, rather than it being deferred) while still deferring all other functionality.
So this is the general pattern:
public static IEnumerable<T> Foo<T>(
this IEnumerable<T> souce, Func<T, bool> anotherArgument)
{
//note, not an iterator block
if(anotherArgument == null)
{
//TODO make a fuss
}
return FooImpl(source, anotherArgument);
}
private static IEnumerable<T> FooImpl<T>(
IEnumerable<T> souce, Func<T, bool> anotherArgument)
{
//TODO actual implementation as an iterator block
yield break;
}
Enumerators, as the others have said, aren't evaluated until the time they start getting enumerated (i.e. the IEnumerable.GetNext method is called). Thus this
List<int> indexes = "a.b.c.d.e".AllIndexesOf(null).ToList<int>();
doesn't get evaluated until you start enumerating, i.e.
foreach(int index in indexes)
{
// ArgumentNullException
}

IEnumerable Method with AsParallel

I got the following extension method:
static class ExtensionMethods
{
public static IEnumerable<IEnumerable<T>> Subsequencise<T>(
this IEnumerable<T> input,
int subsequenceLength)
{
var enumerator = input.GetEnumerator();
SubsequenciseParameter parameter = new SubsequenciseParameter
{
Next = enumerator.MoveNext()
};
while (parameter.Next)
yield return getSubSequence(
enumerator,
subsequenceLength,
parameter);
}
private static IEnumerable<T> getSubSequence<T>(
IEnumerator<T> enumerator,
int subsequenceLength,
SubsequenciseParameter parameter)
{
do
{
lock (enumerator) // this lock makes it "work"
{ // removing this causes exceptions.
if (parameter.Next)
yield return enumerator.Current;
}
} while ((parameter.Next = enumerator.MoveNext())
&& --subsequenceLength > 0);
}
// Needed since you cant use out or ref in yield-return methods...
class SubsequenciseParameter
{
public bool Next { get; set; }
}
}
Its purpose is to split a sequence into subsequences of a given size.
Calling it like this:
foreach (var sub in "abcdefghijklmnopqrstuvwxyz"
.Subsequencise(3)
.**AsParallel**()
.Select(sub =>new String(sub.ToArray()))
{
Console.WriteLine(sub);
}
Console.ReadKey();
works, however there are some empty lines in-between since some of the threads are "too late" and enter the first yield return.
I tried putting more locks everywhere, however I cannot achieve to make this work correct in combination with as parallel.
It's obvious that this example doesn't justify the use of as parallel at all. It is just to demonstrate how the method could be called.
The problem is that using iterators is lazy evaluated, so you return a lazily evaluated iterator which gets used from multiple threads.
You can fix this by rewriting your method as follows:
public static IEnumerable<IEnumerable<T>> Subsequencise<T>(this IEnumerable<T> input, int subsequenceLength)
{
var syncObj = new object();
var enumerator = input.GetEnumerator();
if (!enumerator.MoveNext())
{
yield break;
}
List<T> currentList = new List<T> { enumerator.Current };
int length = 1;
while (enumerator.MoveNext())
{
if (length == subsequenceLength)
{
length = 0;
yield return currentList;
currentList = new List<T>();
}
currentList.Add(enumerator.Current);
++length;
}
yield return currentList;
}
This performs the same function, but doesn't use an iterator to implement the "nested" IEnumerable<T>, avoiding the problem. Note that this also avoids the locking as well as the custom SubsequenciseParameter type.

linq extension method to take elements from the end of the sequence

There is the enumerable extension method
Take<TSource>(
IEnumerable<TSource> source,
int count
)
which takes the first count elements from the start.
Is there a way to take the elements from the end?
or even better a way to take the elements from an offset to the end?
Thanks
finiteList.Reverse().Take(count).Reverse();
or
finiteList.Skip(finiteList.Count() - count)
There is some overhead in doing this so a custom method would be better.
Update: A custom method
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;
}
}
Update: Changed the code a littlebit with ideas from dtb´s answer :-)
Comment to Bear: Look at this example:
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...
You could potentially change the values of lastFive2 and therefore that approach can be unsafe or at least it´s not the functional way.
To Bear:
What I meant about safe is this:
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?
In these cases you would have to make a copy to be sure. But in most cases your way would be fine - and a little bit more efficient than this so +1 :)
An idea is to use a queue which only have internal Enqueue etc.
MoreLINQ provides a TakeLast extension method:
var last10 = finiteList.TakeLast(10);
To take the elements from an offset to the end, Enumerable.Skip should do the trick:
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();
}
A note on performance. Plenty of answers here operating on IEnumerable<> and that is probably what you need and should use.
But if the datasets are large and of type List<> or similar, you can prevent a lot of unnecessary iterating with something like:
// 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];
}
}

Categories

Resources