Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/292.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 用于Excel克隆的正确数据结构_C#_Data Structures_.net 2.0 - Fatal编程技术网

C# 用于Excel克隆的正确数据结构

C# 用于Excel克隆的正确数据结构,c#,data-structures,.net-2.0,C#,Data Structures,.net 2.0,假设我正在用C#编写一个Excel克隆。 我的网格表示如下: private struct CellValue { private int column; private int row; private string text; } private List<CellValue> cellValues = new List<CellValue>(); private结构单元值 { 私有int列; 私人int row; 私有字符串文本; } 私有

假设我正在用C#编写一个Excel克隆。 我的网格表示如下:

private struct CellValue
{
    private int column;
    private int row;
    private string text;
}
private List<CellValue> cellValues = new List<CellValue>();
private结构单元值
{
私有int列;
私人int row;
私有字符串文本;
}
私有列表单元格值=新列表();
每次用户添加文本时,我只是将其打包为CellValue并添加到CellValue中。给定一个CellValue类型,我可以在O(1)时间内确定它的行和列,这很好。但是,给定一列和一行,我需要循环遍历整个单元格值,以找到该列和该行中的文本,这非常慢。另外,给定一个文本,我也需要循环整个内容。是否有任何数据结构可以让我在O(1)时间内完成所有3项任务

更新: 翻阅一些答案,我想我没有找到一个我喜欢的答案。我可以:

  • 保存CellValue的副本不超过2份,以避免同步。在C世界中,我会很好地使用指针
  • 可以动态添加行和列(与Excel不同)

  • 假设数据是二维的,我会有一个二维数组来保存它。

    好吧,你可以将它们存储在三个字典中:两个
    字典
    对象用于行和列,一个
    字典
    对象用于文本。不过,你必须小心地保持三者同步


    我不确定我会不会只使用一个大的二维数组,但是…

    我认为你应该使用一个索引集合来让它运行得相当快,最完美的是


    您需要通过扩展此类来创建自己的集合。这样,您的对象仍将包含行和列(因此您不会丢失任何内容),但您将能够搜索它们。可能您必须创建一个封装类(行、列)并将其作为键(因此使其不可变并覆盖equals并获取哈希代码)

    如果它是一个精确的克隆,则需要一个以数组为基础的CellValue[256]数组列表。Excel有256列,但行数可以增加。

    我会创建

     Collection<Collection<CellValue>> rowCellValues = new Collection<Collection<CellValue>>();
    

    我会选择一个稀疏数组(链表的链表),以提供最大的灵活性和最小的存储空间

    在本例中,您有一个行的链接列表,其中每个元素都指向该行中的单元格链接列表(您可以根据需要反转单元格和行)

    每个行元素中都有行号,每个单元格元素都有一个指向其行元素的指针,因此从单元格中获取行号是O(1)

    类似地,每个单元格元素都有其列号,也就是O(1)

    要立即找到给定行/列上的单元格,没有简单的方法获得O(1),但稀疏数组的速度与它将获得的速度一样快,除非您为每个可能的单元格预分配信息,以便您可以在数组上进行索引查找—这在存储方面是非常浪费的

    您可以做的一件事是使一维非稀疏,例如使列成为主数组(而不是链表),并将它们限制为1000-这将使列查找索引(fast),然后搜索稀疏行


    我不认为仅仅因为文本可以在多个单元格中复制(不同于行/列),就可以得到文本查找的O(1)。我仍然相信稀疏数组将是搜索文本的最快方法,除非您在另一个数组中维护所有文本值的排序索引(同样,这会使它更快,但会以大量内存为代价)。

    如果行和列可以“动态”添加,然后,不应将行/列存储为单元格的数字属性,而应存储为对行或列对象的引用

    例如:

    private struct CellValue
    {
      private List<CellValue> _column;
      private List<CellValue> _row;
      private string text;
    
      public List<CellValue> column {
         get { return _column; }
         set {
             if(_column!=null) { _column.Remove(this); }
             _column = value;
             _column.Add(this);
            }
         }
    
      public List<CellValue> row {
         get { return _row; }
         set {
             if(_row!=null) { _row.Remove(this); }
             _row = value;
             _row.Add(this);
            }
         }
    }
    
    private List<List<CellValue>> MyRows    = new List<List<CellValue>>;
    private List<List<CellValue>> MyColumns = new List<List<CellValue>>;
    
    public CellValue GetCell(int rowIndex, int colIndex) {
      List<CellValue> row = MyRows[rowIndex];
      List<CellValue> col = MyColumns[colIndex];
      return row.Intersect(col)[0];
      }
    
    private结构单元值
    {
    私有列表_列;
    私有列表行;
    私有字符串文本;
    公共列表列{
    获取{return\u column;}
    设置{
    如果(_column!=null){u column.Remove(this);}
    _列=值;
    _列。添加(此);
    }
    }
    公共列表行{
    获取{return\u row;}
    设置{
    如果(_row!=null){u row.Remove(this);}
    _行=值;
    _行。添加(此);
    }
    }
    }
    私有列表MyRows=新列表;
    私有列表MyColumns=新列表;
    
    每个行和列对象都实现为CellValue对象的列表。这些是无序的——特定行中单元格的顺序与列索引不对应,反之亦然

    每个工作表都有一个行列表和一个列列表,按工作表的顺序排列(上面显示为MyRows和MyColumns)

    这将允许您重新排列和插入新行和新列,而无需循环和更新任何单元格

    删除行时,应在该行上的单元格中循环,并在删除行之前将其从各自的列中删除。对于列,反之亦然

    要查找特定的行和列,请查找相应的行和列对象,然后查找它们共同包含的CellValue

    例如:

    private struct CellValue
    {
      private List<CellValue> _column;
      private List<CellValue> _row;
      private string text;
    
      public List<CellValue> column {
         get { return _column; }
         set {
             if(_column!=null) { _column.Remove(this); }
             _column = value;
             _column.Add(this);
            }
         }
    
      public List<CellValue> row {
         get { return _row; }
         set {
             if(_row!=null) { _row.Remove(this); }
             _row = value;
             _row.Add(this);
            }
         }
    }
    
    private List<List<CellValue>> MyRows    = new List<List<CellValue>>;
    private List<List<CellValue>> MyColumns = new List<List<CellValue>>;
    
    public CellValue GetCell(int rowIndex, int colIndex) {
      List<CellValue> row = MyRows[rowIndex];
      List<CellValue> col = MyColumns[colIndex];
      return row.Intersect(col)[0];
      }
    
    public-CellValue-GetCell(int-rowIndex,int-colIndex){
    列表行=MyRows[rowIndex];
    列表列=MyColumns[colIndex];
    返回行相交(列)[0];
    }
    

    (我对.NET3.5中的这些扩展方法有点模糊,但这应该是大概的。)

    如果我没记错的话,有一篇关于Visicalc是如何做到这一点的文章,可能是在80年代早期的Byte杂志上。我相信这是某种稀疏的数组。但是我认为有上下左右的链接,所以任何给定的单元格都有一个指向上面单元格(不管有多少单元格)、下面单元格、左边单元格和右边单元格的指针。

    这有点过早优化的味道

    也就是说,excel的一些特性对于选择好的结构非常重要

    首先,excel以一种适度非线性的方式使用单元格。解析公式的过程包括遍历排列
    public CellValue GetCell(int rowIndex, int colIndex) {
      List<CellValue> row = MyRows[rowIndex];
      List<CellValue> col = MyColumns[colIndex];
      return row.Intersect(col)[0];
      }