Структура данных массива смещения C# - PullRequest
0 голосов
/ 29 января 2020

Мне было любопытно узнать, существует ли эффективный способ хранения данных в контейнере с максимальным количеством значений, и когда это значение будет достигнуто, он начнет удалять самые старые значения, чтобы добавить новые. И все это упорядоченным образом (это означает, что новые данные должны поступать после последних новых данных).

Я знаю, что могу добиться этого, используя очередь

    q.Enqueue(1);   
    q.Enqueue(2);   
    q.Enqueue(3);  // 1 2 3

    q.Dequeue(); // 2 3 
    q.Enqueue(4); // 2 3 4   

, но для итерации через данные впоследствии требуется преобразовать очередь в массив, что я не уверен, насколько это эффективно.

Может быть, лучше иметь массив с фиксированным размером и иметь индекс, который смещается в начало когда массив заполнен и используется некоторое значение по модулю magi c, итерация всегда выполняется в обратном направлении, чтобы запрашивать данные от самых последних к менее свежим. Это было бы менее читабельным, но работающим и более эффективным, я думаю.

Так что мой вопрос был бы, есть ли лучший, более читаемый и эффективный способ? А также, какова эффективность использования ToArray () при использовании других структур данных (например, List, Queue, Stack ..). Когда этого следует избегать?

1 Ответ

0 голосов
/ 03 февраля 2020

В конце я решил реализовать свою идею. Не уверен, что это лучший способ, но он хорошо подходит для моих нужд:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class DataHolder<T> : IEnumerable
{
    private T[] _data;
    private int _maxSize;
    private int _currIdx;
    private int _currSize;

    public DataHolder(int size)
    {
        _maxSize = size;
        _data = new T[_maxSize];
        _currIdx = -1;
        _currSize = 0;
    }

    public void Add(T data)
    {
        if (_currSize < _maxSize) _currSize++;

        _currIdx = NioUtils.PositiveMod((_currIdx + 1),  _maxSize);
        _data[_currIdx] = data;
    }

    ///<summary>
    /// Gets the element at index. The 0 element is the last one added.
    ///</summary>
    public T GetElementAt(int index)
    {
        if (index >= _currSize)
        {
            throw new System.ArgumentException("Index out of bounds exception.", "index");
        }

        int shiftIndex = NioUtils.PositiveMod((_currIdx - index), _maxSize);
        return _data[shiftIndex];
    }

    /// Implement interface IEnumerable in order to iterate throught this object.
    public IEnumerator GetEnumerator()
    {
        int count = 0;
        int index = _currIdx;
        while (count < _currSize)
        {
            count++;
            yield return _data[index];
            index = NioUtils.PositiveMod((index - 1), _maxSize);
        }
    }

}

Где PositiveMod:

public static int PositiveMod(int value, int n)
{
    int v = value % n;
    return v >= 0 ? v : n + v;
}
...