PeekRange на стеке в C #? - PullRequest
       4

PeekRange на стеке в C #?

0 голосов
/ 26 ноября 2010

У меня есть программа, которая должна хранить значения данных и периодически получать последние значения данных «х».

Первоначально считалось, что стек - это путь, но мне нужно иметь возможность видеть больше, чемтолько верхнее значение - что-то вроде метода PeekRange, где я могу посмотреть последнее число значений «х».

В данный момент я просто использую список и получаю последние, скажем, 20 значений, например:

var last20 = myList.Skip(myList.Count - 20).ToList();

Список постоянно увеличивается при запуске программы, но мне нужны только последние 20 значений.Может ли кто-нибудь дать совет о лучшей структуре данных?

Ответы [ 5 ]

4 голосов
/ 26 ноября 2010

Возможно, я бы использовал кольцевой буфер .Это несложно реализовать самостоятельно, AFAIK. Реализация не предусмотрена платформой.

1 голос
/ 26 ноября 2010

Вы сказали, что стека, но вы также сказали, что вы хотите только последние 20 предметов. Я не думаю, что эти два требования действительно соответствуют друг другу.

Я бы сказал, что Йоханнес прав насчет кольцевого буфера. ОЧЕНЬ легко реализовать это самостоятельно в .NET; просто используйте Queue<T>, и как только вы достигнете своей емкости (20), начните убирать (выталкивать) при каждом включении в очередь (пуш).

Если вы хотите, чтобы ваш PeekRange перечислял от самого последнего к наименее последнему, вы можете определить GetEnumerator, чтобы сделать что-то вроде return _queue.Reverse().GetEnumerator();

1 голос
/ 26 ноября 2010

Ну, так как вы упомянули стек, я думаю, вам нужны только изменения в конце списка?

В этом случае список на самом деле является хорошим решением (эффективный кэш и с быстрой вставкой / удалениемконец).Однако ваш способ извлечения последних нескольких элементов несколько неэффективен, потому что IEnumerable<T> не будет предоставлять произвольный доступ, предоставленный списком.Таким образом, Skip() -Implementation должен сканировать весь List, пока он не достигнет конца (или сначала выполнить проверку типа во время выполнения, чтобы обнаружить, что контейнер реализует IList<T>).Более эффективно либо получить доступ к элементам напрямую по индексу, либо (если вам нужен второй массив) использовать List<T>.CopyTo().

Если вам нужно быстрое удаление / вставка в начале, вы можете захотетьрассмотрим кольцевой буфер или (дважды) связанный список (см. LinkedList<T>).Связанный список будет менее эффективен для кэширования, но его легко и эффективно перемещать и изменять в обоих направлениях.Кольцевой буфер немного сложнее реализовать, но он будет более кэш- и пространственно-эффективным.Так что, вероятно, лучше, если будут храниться только небольшие типы значений или ссылочные типы.Особенно, когда размер буферов фиксирован.

1 голос
/ 26 ноября 2010

Вы можете просто удалить (0) после каждого добавления (если список длиннее 20), поэтому список никогда не будет длиннее 20 элементов.

0 голосов
/ 26 ноября 2010

Woops, .Take () не будет этого делать.

Вот реализация .TakeLast ()

http://www.codeproject.com/Articles/119666/LINQ-Introducing-The-Take-Last-Operators.aspx

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...