【问题标题】:Speed and functionality of dictionary vs list vs array字典 vs 列表 vs 数组的速度和功能
【发布时间】:2012-11-29 13:28:19
【问题描述】:

我正在使用 .NET 4.5 用 C# 编写应用程序。我的应用程序读取和写入硬件设备使用的二进制文件。该文件正好是 5,000,000 字节,由 100,000 个 50 字节的“块”组成。每个 50 字节的块将包含一个 ASCII 编码的字符串(可能只是一个空字符串)。设备需要文件布局,因此可以通过确定偏移量(索引 * 50 字节,然后读取/写入接下来的 50 字节)来访问任何字符串。

我的 WinForms 应用程序需要能够:

  • 从文件中加载所有 100,000 个字符串并将它们显示在 UI(列表框)中
  • 添加、编辑或删除字符串
  • 以正确的格式重写二进制文件

注意事项:

  1. 二进制文件中相当多的数据最初是空字符串,我不想向用户显示,但仍需要在我的数据结构中,以便我可以正确地重写文件。
  2. 在添加新字符串之前,我需要确保有可用空间来允许它(即,至少有一个 50 字节的空块)。如果没有,那么用户将需要“删除”现有字符串,以便为要添加的新字符串腾出空间。
  3. 在后台添加、修改和删除字符串是相同的操作。添加只是将 50 字节的空数据更改为 50 字节的字符串数据,而删除则相反。
  4. 除空字符串外,不应存储重复的字符串,因此我需要某种方法来遍历我的数据结构,以确保在添加或编辑字符串以匹配现有字符串之前该字符串不存在.

所以我需要一个数据结构来保存文件中的所有数据,我正在努力在字典、列表或数组之间做出决定。鉴于上述警告,我不认为直接将任何数据结构绑定到 UI 是一个可行的解决方案。所以我认为我需要在该数据结构和列表框之间使用大量代码来实现某种伪绑定。如果是这种情况,从功能的角度来看,哪种数据结构(字典、列表、数组等)最有用,并提供最佳折衷:使用这种大小的数据集(100,000 个最多 50 个 ASCII 字符的字符串)的速度每个)?

【问题讨论】:

  • 您可以简单地停在“...100,000 个字符串...在...列表框中显示它们”。它的可用性和性能将胜过所有其他成本......

标签: c# .net list dictionary listbox


【解决方案1】:

如果性能很关键,最好的办法就是测试一下。编写一个快速而肮脏的应用程序,以所有三种方式完成关键工作,然后将其包装在一个循环中,完成 10,000 次,看看哪个更快。

【讨论】:

    【解决方案2】:

    这里似乎不需要字典,因为您没有任何键来索引数据。
    列表适用于添加/删除项目,但这显然也不是必需的。
    所以我会选择一个字符串数组

    编辑:重新考虑存在的多个空字符串,如果空字符串与填充字符串的比率不低,我可以建议进行可能的优化。
    我们可以使用整数数组作为映射,而不是只包含填充字符串的字典

    警告:需要测试

    int[] keys = new int[100];  // Just 100 to test the idea
    Dictionary<int, string> data = new Dictionary<int, string>();
    
    AddItem(keys, 32, data, "Position 32 34567890123456789012345678901234567890");
    AddItem(keys, 40, data, "Position 40 34567890123456789012345678901234567890");
    AddItem(keys, 10, data, "Position 10 34567890123456789012345678901234567890");
    AddItem(keys, 25, data, "Position 25 34567890123456789012345678901234567890");
    AddItem(keys, 99, data, "Position 99 34567890123456789012345678901234567890");
    AddItem(keys, 0, data, "Postion 00 234567890123456789012345678901234567890");
    AddItem(keys, 18, data, "Position 18 34567890123456789012345678901234567890");
    
    foreach(int x in keys)
    {
        if(x == 0)
            Console.WriteLine("Empty string");
        else
            Console.WriteLine(data[x]);
    }
    
    void AddItem(int[] keys, int keyPos, Dictionary<int, string> data, string message)
    {
        int count = data.Count;
        data.Add(count, message);
        keys[keyPos] = count;
    }
    void RemoveItem(int[] keys, int keyPos, Dictionary<int, string> data)
    {
        int x = keys[keyPos];
        data.Remove(x);
        keys[keyPos] = 0;
    }
    void UpdateItem(int[] keys, int keyPos, Dictionary<int, string> data, string message)
    {
        int x = keys[keyPos];
        data[x] = message;
    }
    

    【讨论】:

    • 听起来他们可能想要对字符串数据本身进行键控,因为他们不想存储/使用重复的字符串。
    • @ChrisSinclair,是的,我正在考虑利用多个空字符串的事实来实现一些结合数组和字典的优化,看看我的编辑
    • 可能需要翻转它(或使其双向):如果您想查看当前是否正在使用字符串,则必须对字典值进行 O(N) 迭代看看它们是否匹配。
    【解决方案3】:

    即使有 100,000 个条目,我认为您也不必过多担心性能问题。 (编辑:我的意思是,在 I/O 或数据更改方面的性能。您的 GUI 绑定可能会遇到问题)

    以最简单的方式对其进行编程,使您可以最轻松地更改业务逻辑和 GUI 绑定。甚至可以考虑创建您自己的类,该类简单地包装 List(或 Array 或其他),并为您的 GUI 提供一个隐藏此实现细节的标准公共接口。

    一旦您的 GUI 运行并且所有 I/O 都运行良好(理想情况下,有一些不错的单元测试套件),那么您就可以开始进行基准测试/分析并找出瓶颈所在。

    编辑:考虑到您的要求,这种自定义/包装的数据结构可能是理想的。它可以主动了解您数据的某些方面。例如,当它被加载/读取时,它可以检查是否有空间可用于新字符串,所以当用户去添加更多时,你已经知道是否可以。它可以维护一个 HashSet 使用的唯一字符串,因此您可以很好地 O(1) 查找重复字符串,等等。

    【讨论】:

      【解决方案4】:

      实际上,字典是存储数据的最佳选择。键是要存储的字符串,值是它的位置。您可以通过字典的大小来跟踪您的可用空间。

      对于您的列表框,您首先将字典转换为数组,然后将该数组用作列表框的后备存储。这将是您在应用程序启动时支付的一次性速度损失,但会大大提高您的 UI 响应速度并满足基础数据存储的其他要求。

      在字典上执行添加/删除操作,快速处理重复检查,如果您对底层字典进行更改而不是重建数组,您可以快速直接更新数组。

      【讨论】:

        猜你喜欢
        • 2013-04-02
        • 2014-04-20
        • 1970-01-01
        • 1970-01-01
        • 2010-12-26
        • 1970-01-01
        • 2015-10-24
        • 1970-01-01
        • 2016-05-16
        相关资源
        最近更新 更多