管理带有移动项目的列表的(几乎)最佳方式

时间:2012-09-20 17:40:27

标签: c# performance list

情况如下:
我有一个列表,其中存储的字符串实际上是数字,可以变得相当大(数亿项) 我将数字存储为字符串,因为有一个选项可以显示一些附加信息,即文本。

因为这需要大量的内存来存储我决定我最多只能存储500万个项目。 (这只需要250-300mb)。

列表由计算输出填充。如果找到一个数字,它将被添加到列表中,此数字总是大于现有项目。

当列表达到5密耳时,我想删除第一个项目并将新项目添加到列表中。

像:

    // Why is this so freaking slow???
    if (_result.Count == 5000000)
        _result.RemoveAt(0);
    _result.Add(result);

正如你在评论中看到的那样,这非常非常非常慢。它只是将我的表现减少了15倍。花了2分钟,现在需要大约30分钟。

我尝试使用像.Skip(1).ToList这样的linq,但是会重新创建列表,因此更慢。

列表必须保持正确的顺序,因此不能通过索引覆盖(除非你能解释一个很好的解决方法)。

我的问题:
有没有可行的方法呢?

我真的需要这里的表现,因为它可能需要检查大约10000000000个数字。这可能需要一天的时间,但一个月有点太多了:(。

需要其他信息,请随时提出,我很乐意提供。

解决方案:
这执行O(1)

    // Set the _result
    Queue<object> _result = new Queue<object>(5000000);

    /// Inside the method
    // If the count has reach it's max, dequeue the first item
    if (_result.Count == 5000000)
        _result.Dequeue();
    _result.Enqueue(result);

5 个答案:

答案 0 :(得分:4)

你有没有重新订购商品?如果不这样做,循环队列可以很好地工作。

System.Collections.Generic.Queue是一个,我只是仔细检查过。

为了扩展Queue的优势,这是RemoveAt实现(大致):

for (int i = 1; i < count; i++)
    items[i-1] = items[i];
count--;

由于list[0]始终是第一项,因此您必须移动所有内容以删除第一项。

相反,队列分别跟踪第一个项目。这会将上面的代码更改为:

head++

答案 1 :(得分:1)

我建议你更好地实现循环队列。然后你将每个int推到队列的末尾,当你用完空间(由固定大小决定)时,每个操作都需要弹出第一个并按下底部。 O(1)

Advantage vs. Array是指在需要之前不会预先分配空间。但是,最后,考虑真的将整体存储为整体。无论您执行什么操作,都应始终将数字存储为数字。

答案 2 :(得分:0)

为什么不预先分配数组,并且有两个整数,表示数组的开始和结束。显然,他们都会开始等于0.一旦你用完房间,你就会开始环绕。

示例psuedo助手类:

class CircularArray
{
  const int maxSize = 5000000;
  private int[] arr = new int[maxSize];
  private int start = 0;
  private int end = 0;

  public void Add(int value)
  {
    int newEnd = (end + 1) % maxSize;
    if (newEnd == start)
      start = (start + 1) % maxSize;
    end = newEnd;
    arr[end] = value;
  }

  public int Get(int index)
  {
    int newIndex = (start + index) % maxSize;
    return arr[newIndex];
  }
}

答案 3 :(得分:0)

当您删除ArrayList中的第一个项目时,所有其他项目都会向下移动。循环查询将允许您保留原始顺序,并消除删除列表头部时发生的耗时变化。

答案 4 :(得分:0)

可能LinkedList<T> Class可能对您有帮助吗?在两端删除和添加是O(1)操作,但是迭代将是O(n),或者如果您在访问时需要O(1),则可以使用DictionarySortedDictionary 另一个自定义实现是QueueDictionary,当我在最后添加和删除或者开始(Queue / Dequeue)和访问值时都需要O(1)操作时,我使用它。这里的QueueDictionary:How would I implement a QueueDictionary, a combination of Queue and Dictionary in C#?