इस समस्या के लिए मैं जिस समाधान का उपयोग करता हूं वह थोड़ा अधिक विस्तृत है।
मेरे उपयोग स्थिर वर्ग में एक विस्तार विधि शामिल है MarkEndजो T-items को -items में EndMarkedItem<T>रूपांतरित करता है। प्रत्येक तत्व एक अतिरिक्त के साथ चिह्नित है int, जो या तो 0 है ; या (यदि कोई अंतिम 3 मदों में विशेष रूप से रुचि रखता है) -3 , -2 , या -1 अंतिम 3 वस्तुओं के लिए।
यह अपने आप ही उपयोगी हो सकता है, उदाहरण के लिए , जब आप foreachअंतिम 2 को छोड़कर प्रत्येक तत्व के बाद अल्पविराम के साथ एक साधारण- लूप में एक सूची बनाना चाहते हैं , जिसके बाद एक संयोजन शब्द (जैसे " और ") के बाद दूसरा आइटम होता है या " या "), और अंतिम तत्व एक बिंदु के बाद।
अंतिम n आइटम के बिना पूरी सूची तैयार करने के लिए , विस्तार विधि ButLastबस उस EndMarkedItem<T>समय से अधिक पुनरावृत्त होती है EndMark == 0।
यदि आप निर्दिष्ट नहीं करते हैं tailLength, तो केवल अंतिम आइटम को (में MarkEnd()) या गिराया गया है ButLast()।
अन्य समाधानों की तरह, यह बफरिंग द्वारा काम करता है।
using System;
using System.Collections.Generic;
using System.Linq;
namespace Adhemar.Util.Linq {
public struct EndMarkedItem<T> {
public T Item { get; private set; }
public int EndMark { get; private set; }
public EndMarkedItem(T item, int endMark) : this() {
Item = item;
EndMark = endMark;
}
}
public static class TailEnumerables {
public static IEnumerable<T> ButLast<T>(this IEnumerable<T> ts) {
return ts.ButLast(1);
}
public static IEnumerable<T> ButLast<T>(this IEnumerable<T> ts, int tailLength) {
return ts.MarkEnd(tailLength).TakeWhile(te => te.EndMark == 0).Select(te => te.Item);
}
public static IEnumerable<EndMarkedItem<T>> MarkEnd<T>(this IEnumerable<T> ts) {
return ts.MarkEnd(1);
}
public static IEnumerable<EndMarkedItem<T>> MarkEnd<T>(this IEnumerable<T> ts, int tailLength) {
if (tailLength < 0) {
throw new ArgumentOutOfRangeException("tailLength");
}
else if (tailLength == 0) {
foreach (var t in ts) {
yield return new EndMarkedItem<T>(t, 0);
}
}
else {
var buffer = new T[tailLength];
var index = -buffer.Length;
foreach (var t in ts) {
if (index < 0) {
buffer[buffer.Length + index] = t;
index++;
}
else {
yield return new EndMarkedItem<T>(buffer[index], 0);
buffer[index] = t;
index++;
if (index == buffer.Length) {
index = 0;
}
}
}
if (index >= 0) {
for (var i = index; i < buffer.Length; i++) {
yield return new EndMarkedItem<T>(buffer[i], i - buffer.Length - index);
}
for (var j = 0; j < index; j++) {
yield return new EndMarkedItem<T>(buffer[j], j - index);
}
}
else {
for (var k = 0; k < buffer.Length + index; k++) {
yield return new EndMarkedItem<T>(buffer[k], k - buffer.Length - index);
}
}
}
}
}
}