Из ссылки svrist:
первый объект в http://java.sun.com/performance/jvmstat/faq.html упоминания опция, которую можно выключить для отключения целого комплекта функций:-XX:-UsePerfData.
Я не знаю решения Linq. Но вы можете легко запрограммировать алгоритм самостоятельно, используя генераторы (yield return).
public static IEnumerable<T> TakeAllButLast<T>(this IEnumerable<T> source) {
var it = source.GetEnumerator();
bool hasRemainingItems = false;
bool isFirst = true;
T item = default(T);
do {
hasRemainingItems = it.MoveNext();
if (hasRemainingItems) {
if (!isFirst) yield return item;
item = it.Current;
isFirst = false;
}
} while (hasRemainingItems);
}
static void Main(string[] args) {
var Seq = Enumerable.Range(1, 10);
Console.WriteLine(string.Join(", ", Seq.Select(x => x.ToString()).ToArray()));
Console.WriteLine(string.Join(", ", Seq.TakeAllButLast().Select(x => x.ToString()).ToArray()));
}
Или как обобщенное решение, отбрасывающее последние n элементов (с использованием очереди, подобной предложенной в комментариях):
public static IEnumerable<T> SkipLastN<T>(this IEnumerable<T> source, int n) {
var it = source.GetEnumerator();
bool hasRemainingItems = false;
var cache = new Queue<T>(n + 1);
do {
if (hasRemainingItems = it.MoveNext()) {
cache.Enqueue(it.Current);
if (cache.Count > n)
yield return cache.Dequeue();
}
} while (hasRemainingItems);
}
static void Main(string[] args) {
var Seq = Enumerable.Range(1, 4);
Console.WriteLine(string.Join(", ", Seq.Select(x => x.ToString()).ToArray()));
Console.WriteLine(string.Join(", ", Seq.SkipLastN(3).Select(x => x.ToString()).ToArray()));
}
Ничего в BCL (или, как мне кажется, MoreLinq), но вы можно создать свой собственный метод расширения.
public static IEnumerable<T> TakeAllButLast<T>(this IEnumerable<T> source)
{
using (var enumerator = source.GetEnumerator())
bool first = true;
T prev;
while(enumerator.MoveNext())
{
if (!first)
yield return prev;
first = false;
prev = enumerator.Current;
}
}
}
В качестве альтернативы созданию собственного метода и в случае, если порядок элементов не важен, будет работать следующий:
var result = sequence.Reverse().Skip(1);
Поскольку я не поклонник явного использования Enumerator
, вот альтернатива. Обратите внимание, что методы-оболочки необходимы для того, чтобы позволить недопустимым аргументам возникать раньше, а не откладывать проверки до тех пор, пока последовательность не будет фактически перечислена.
public static IEnumerable<T> DropLast<T>(this IEnumerable<T> source)
{
if (source == null)
throw new ArgumentNullException("source");
return InternalDropLast(source);
}
private static IEnumerable<T> InternalDropLast<T>(IEnumerable<T> source)
{
T buffer = default(T);
bool buffered = false;
foreach (T x in source)
{
if (buffered)
yield return buffer;
buffer = x;
buffered = true;
}
}
Согласно предложению Эрика Липперта, это легко обобщается на n элементов:
public static IEnumerable<T> DropLast<T>(this IEnumerable<T> source, int n)
{
if (source == null)
throw new ArgumentNullException("source");
if (n < 0)
throw new ArgumentOutOfRangeException("n",
"Argument n should be non-negative.");
return InternalDropLast(source, n);
}
private static IEnumerable<T> InternalDropLast<T>(IEnumerable<T> source, int n)
{
Queue<T> buffer = new Queue<T>(n + 1);
foreach (T x in source)
{
buffer.Enqueue(x);
if (buffer.Count == n + 1)
yield return buffer.Dequeue();
}
}
Где я теперь буфер перед уступкой вместо уступки после уступки, так что случай n == 0
не требует специальной обработки.
Почему бы просто не .ToList
на последовательности, затем вызвать count и take, как вы делали изначально... но поскольку он был собран в список, он не должен делать дорогое перечисление дважды. Верно?