在固定大小的数组中存储“N”个记录

时间:2012-01-12 01:34:40

标签: c#

是否可以在数组中存储一组滚动值而不超过设置索引?

例如,我将基本的控制台示例放在一起,如下所示:

static void Main(string[] args)
{
    int[] myvalue;
    myvalue = new int[10];

    for (int i = 0; i < 20; i++)
    {
        Console.WriteLine("Array {0} is {1}", i, myvalue[i]);         
    }
    Console.ReadLine();

}

在当前的方法中,我获得了一个超出范围的索引异常。我想要做的是将数组限制为10个项目,但随着计数的增加,用新值覆盖现有项目。因此,我可以迭代100次,但数组只会在例程结束时显示最后十个值(89-99)。

如果数组不是最佳方法,我欢迎任何有关如何将其存储在内存中的建议。

谢谢

6 个答案:

答案 0 :(得分:6)

您可以使用List来存储值,然后包装Add方法来处理项目数量的限制。这将为您处理所有“向下滑动”的逻辑。

const int MAX_ITEMS = 10;
List<int> list = new List<int>();

void AddItem(int k)
{
    list.Add(k);
    if (list.Count > MAX_ITEMS)
    {
        // discard the item at the front of the list
        list.RemoveAt(0);
    }
}

每当您想要添加值时,只需拨打AddItem(n),例如:

for (int i = 0; i < 100; i++)
{
    AddItem(i);
}

每当您想要读出值时,您只需执行以下操作:

for (int i = 0; i < list.Count; i++)
{
    Console.WriteLine(list[i]);
}

这也有一个优点,你可以放入少于最大数量的项目(比如你只有6而不是10)并且它仍然可以正常工作(你不必担心未填充的数组项目)。

答案 1 :(得分:6)

听起来像circular buffer。在codeplex上的C#中有一个existing implementation

答案 2 :(得分:3)

如果您希望数组始终按照遇到的顺序保存最后十个值 ,那么每次将array[N]复制到{时,您必须“向下滑动数值”数组{1}}所有N&gt; = 1,然后在最后一个位置写入“最新”值。

如果您不需要数组具有此特定顺序的值,则可以使用模数技巧并写入任何array[N-1]的{​​{1}};一旦你到达终点,它就会“循环”到数组的开头。

最后,如果想要按顺序的值,您需要一个不会强制您复制每次迭代的所有元素的数据结构,您可以使用:

  • a linked list,如果索引访问不是必需的
  • 一个双端队列(又名deque),如果你还需要索引访问 - .NET没有内置的,但有一个经过验证的实现作为PowerCollections的一部分

答案 3 :(得分:1)

您可以使用循环链接列表而不是数组。

在下面的代码段中,currentNode始终是输入的最后一个节点。这样,当您按照链接列表进行完整循环时,您可以使列表任意长,并且永远不必担心结束的位置,因为在某些时候您会自动开始覆盖旧值。

static void Main(string[] args)
{
    //create first node
    var firstNode = new Node();
    var lastNode = firstNode;

    //create linked list
    for(int i=0; i<9; i++)
    {
        var nextNode = new Node();
        lastNode.nextNode = nextNode;
        lastNode = nextNode;
    }

    //link tail of list to beginning to make the circular reference.
    lastNode.nextNode = firstNode;

    var currentNode = firstNode;

    //your code goes here
    for(int j=0; j<1000; j++)
    {
        currentNode.value = j; //now you set your values in your loop
        currentNode = currentNode.nextNode; //and move on to the next node
    }
}

public class Node
{
    public int value;
    public Node nextNode;
}

答案 4 :(得分:0)

你可以这样试试:

myvalue = new int[10];
for (int i = 0; i < 100; i++)
    myvalue[i % myvalue.Length] = i; 

当然,这将从头到尾开始,因此数组可能不是您将值写入其中的顺序,而是有些旋转。如果您想避免这种情况,则需要将元素从myvalue[1]复制到myvalue[myvalue.Length-1]myvalue[1]myvalue[myvalue.Length-2],并在每次插入新元素时覆盖myvalue[myvalue.Length-1] 。或者,您可以在完成所有插入后旋转阵列以固定定位。

答案 5 :(得分:0)

这可能不是最优雅的代码,但它说明了如何创建一个记录n个最新值的循环缓冲区:

const int SIZE = 10;
int[] myValue = new int[SIZE];
int start = 0;
int count = 0;

void NewValue(int v)
{
    myValue[start] = v;
    if (count < SIZE)
        count++;
    start = (++start) % SIZE;
}

void ListValues()
{
    for (int i = start - 1; i >= 0; i--)
        Console.WriteLine(myValue[i]);
    if (count >= SIZE)
        for (int i = SIZE - 1; i >= start; i--)
            Console.WriteLine(myValue[i]);
    Console.WriteLine();
}

private void Test()
{
    for (int i = 0; i < 20; i++)
    {
        NewValue(i);
        ListValues();
    }
}