Here's one way to do this, which has the advantage that it doesn't create copies of the entire source string, is so pretty efficient. Most of the code will be placed in a class along with other general-purpose extension methods, so the end result is that you can do this with 1 line of code
using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace ConsoleApplication1 { class Program { static void Main(string[] args) { string x = "a\r\nb\r\nc\r\nd\r\ne\r\nf\r\ng\r\nh\r\ni\r\nj\r\nk\r\nl\r\nm\r\nn\r\no\r\np"; foreach(var line in x.SplitAsEnumerable("\r\n").TakeLast(10)) Console.WriteLine(line); Console.ReadKey(); } } static class LinqExtensions { public static IEnumerable<string> SplitAsEnumerable(this string source) { return SplitAsEnumerable(source, ","); } public static IEnumerable<string> SplitAsEnumerable(this string source, string seperator) { return SplitAsEnumerable(source, seperator, false); } public static IEnumerable<string> SplitAsEnumerable(this string source, string seperator, bool returnSeperator) { if (!string.IsNullOrEmpty(source)) { int pos = 0; do { int newPos = source.IndexOf(seperator, pos, StringComparison.InvariantCultureIgnoreCase); if (newPos == -1) { yield return source.Substring(pos); break; } yield return source.Substring(pos, newPos - pos); if (returnSeperator) yield return source.Substring(newPos, seperator.Length); pos = newPos + seperator.Length; } while (true); } } public static IEnumerable<T> TakeLast<T>(this IEnumerable<T> source, int count) { List<T> items = new List<T>(); foreach (var item in source) { items.Add(item); if (items.Count > count) items.RemoveAt(0); } return items; } } }
EDIT: It has been pointed out that this may be more efficient as iterates over the entire string. I also believe that RemoveAt (0) with a list is probably also inefficient. To solve this problem, the code can be modified to search backward by string. This would eliminate the need for a TakeLast function, since we could just use Take.
Mikekulls
source share