이 문제에 사용하는 솔루션은 약간 더 정교합니다.
내 util 정적 클래스에는 -items를 -items MarkEnd
로 변환 하는 확장 메소드 가 포함되어 있습니다 . 각 요소는 추가로 표시되는 어느 하나이고, 0 ; 또는 (마지막 3 개 항목에 특히 관심이있는 경우) -3 , -2 또는 -1 마지막 3 개 항목.T
EndMarkedItem<T>
int
이는, 자신에 유용 할 수있다 예를 들어 간단한에서 목록을 만들 때 foreach
마지막 두 제외한 각 요소 다음 쉼표로 -loop을 (같은 관련 단어 다음에 마지막에서 두 번째 항목 " 및 " 또는 " 또는 " "), 마지막 요소 다음에 점이옵니다.
마지막 n 개의 항목 없이 전체 목록을 생성하기 위해 확장 메소드는 ButLast
단순히 EndMarkedItem<T>
s 동안 반복합니다 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);
}
}
}
}
}
}