【问题标题】:Data structure for a huge dataset庞大数据集的数据结构
【发布时间】:2014-01-22 10:09:21
【问题描述】:

我需要为一个类创建一个有效的数据结构,该类存储一个大小从 50,000 到 100,000 个值不等的集合。

class TypeData
{
    public string Name { get; set; }
    public Collection<double> Data{ get; set; }
}

现在,用户想要对该数据执行一些操作,然后该操作将集合中的实际值替换为“0”。例如

Before operation:
3.4
5.6
66.71
101.44
3.567
345.09

After operation:
3.4
0.0
0.0
101.44
0.0
345.09

现在,用户想要恢复该操作。然后我必须删除所有 0.0 并将原始值放在集合中的这些索引上。

问题 1: 如何跟踪更改的索引?我是否需要保留另一个包含所有更改索引的列表? 问题2: 如何改进此类的数据结构,使其可以容纳数千个实例,即

List&lt;TypeData&gt; dataList = new List&lt;TypeData&gt;(); // 这个列表的大小可以增加到 5000

【问题讨论】:

    标签: c# data-structures collections dataset


    【解决方案1】:

    如果您只需要撤消操作一次,那么使用 Tim Schmelter 的 active/actual 值的解决方案是正确的。

    如果你需要多个撤消,那么你必须实现一个history。同样的方式你也可以提供 redo 的可能性。

    有一些假设撤消实际上可以很容易的任务。如果 undo 之间列表中的项目数没有改变,那么您可以将所有更改保存在历史记录(基本上是另一个列表)index 和 value 中。撤消操作将遍历历史,获取索引并恢复值。

    如果要更改项目的数量,那么最简单的方法是通过制作副本来保存完整的状态数据。但是,这是一个消耗内存的操作,但如果您考虑使用数据库或文件来保存此类状态,仍然可以实现。

    其他解决方案是实现操作,您可以将其保存在历史记录中。您仍然需要保存 state,但它只是那个大小,需要 operation(例如,在删除不需要存储的项目的情况下)整个列表,只有已删除项目的索引和值)。在这种情况下,撤消看起来像是从历史上一次操作中读取并向后执行(或者您可以从一开始就反转历史记录,准备撤消,例如,在删除项目的情况下,您改为保存插入操作)。在列表操作的情况下,可能操作的基本列表可能是:清除、插入、删除、更改值。

    【讨论】:

      【解决方案2】:

      问题 1:如何跟踪更改的索引?我需要保留一个 另一个包含所有更改索引的列表?

      我不会存储Collection&lt;double&gt;,而是存储值、当前状态和历史记录(如果有)的Collection&lt;CustomType&gt;。

      例如:

      public class TypeData
      {
          public string Name { get; set; }
          public List<Data> Data { get; set; }
      }
      
      public class Data
      {
          public enum State
          {
              Unassigned,
              Original,
              Modified
          }
      
          private double _Value = 0.0d;
          public double Value
          {
              get { return _Value; }
              set
              {
                  if (CurrentState == State.Unassigned)
                      CurrentState = State.Original;
                  else
                      CurrentState = State.Modified;
                  _Value = value;
                  _ValueHistory.Add(value);
                  if (_ValueHistory.Count > MaxHistoryCount)
                      ClearValueHistory();
              }
          }
      
          private List<double> _ValueHistory = new List<double> { 0.0d };
          private List<double> ValueHistory
          {
              get { return _ValueHistory; }
              set { _ValueHistory = value; }
          }
      
          private int _MaxHistoryCount = int.MaxValue;
          public int MaxHistoryCount
          {
              get { return _MaxHistoryCount; }
              set { _MaxHistoryCount = value; }
          }
      
          public void ClearValueHistory()
          {
              if (_ValueHistory.Count > 1)
                  _ValueHistory.RemoveRange(0, _ValueHistory.Count - 1); // keep last
          }
      
          private State _CurrentState = State.Unassigned;
          public State CurrentState
          {
              get { return _CurrentState; }
              private set { _CurrentState = value; }
          }
      
          public void RevertOperation(int numRevertCount = 1)
          {
              int newRevisionIndex = _ValueHistory.Count - 1 - numRevertCount;
              if (newRevisionIndex < 0) newRevisionIndex = 0;
              double val = _ValueHistory[newRevisionIndex];
              _ValueHistory.RemoveRange(newRevisionIndex + 1, _ValueHistory.Count - 1 - newRevisionIndex);
              this._Value = val;
          }
      
          public override string ToString()
          {
              return Value.ToString();
          }
      }
      

      这是示例数据和示例性反向操作:

      var listOfData = new List<TypeData>{ 
          new TypeData {
              Name = "TestData",
              Data = new List<Data> 
              {
                  new Data { Value = 1.5 }, new Data { Value = 2.4 }, new Data { Value = 1.2 },  new Data(),
                  new Data { Value = 0.7 }, new Data { Value = -4.7 }, new Data { Value = 0.0 }, new Data { Value = 4711}
              }
          }
      };
      
      foreach (var td in listOfData)
      {
          foreach (var data in td.Data.Take(10))
          {
              data.Value = 4711.4711;
          }
      }
      foreach (var td in listOfData)
      {
          foreach (var data in td.Data.Take(10))
          {
              data.RevertOperation();
          }
      }
      

      问题2:如何改进这个类的数据结构,使其 可以容纳数千个实例,即

      为什么需要改进它?我会保持原样。我怀疑它需要太多的内存。否则,您应该决定是购买更多内存还是使用数据库。

      【讨论】:

      • 我本可以使用 struct 来实现这一点,它有一个布尔值来表示一个改变的值。但是我有一些硬性要求,有两种操作,第一种操作将在随机索引处将值标记为 0.0,第二种操作将在索引范围内标记 0.0。那么如果用户只想恢复第一个操作怎么办。布尔无法判断,是什么操作使这个值变为 0.0
      • enum DataType { Original, Operation1, Operation2 } struct Data { double value;数据类型类型;这会工作吗?如果将来有新需求或可能是第三次操作怎么办?
      • 说实话,我会改用数据库。但是,我已经编辑了我的答案,以显示存储该值历史的类的可能实现。请注意,它应该给你一个想法,它没有经过彻底的测试。
      • 实际上,我无法在此工作流程中使用数据库。实际情况是,用户将调查数据作为 blob 存储在数据库中,用户想要加载 5000 个调查的数据。我只是反序列化了每个调查数据,将其带入内存并显示在图表上。因此,在将其显示到图表之前,我已经填写了所有 collection :(
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-05-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多