以下情况下最适合使用哪些C#数据结构?

8
我的应用程序需要满足以下要求。我需要存储类似下面的订单:
- 每个订单都与特定的股票代码(字符串)相关联,并具有价格、数量和是否正在购买或出售(布尔值)等属性。 - 我需要对所有与特定股票有关的订单执行若干操作,例如获取股票代码为“abc”的订单总数量。 - 我需要能够向数据结构中添加订单。 - 我需要能够从数据结构中删除订单。 - 在添加或删除订单后,我需要知道哪个订单提供了最优价格。
目前,我的想法如下:
public class Order : IComparable
{

   private string _StockCode;
   private bool _BidSide;
   private int _Volume;
   private decimal _Price;
   private int _ExchangeOrderId;

   public int CompareTo(Order other)
   {
        if (_BidSide != other.BidSide)
        {
            return _BidSide ? 1 : -1;
        }
        return decimal.Compare(_Price, other.Price);
   }
}

然后,我会将订单存储在一个Dictionary>中。其中,每个股票代码都是字典中的一个键,指向该股票的订单列表。我还会维护一个字典,将订单ID与股票代码匹配。
对于添加新订单,我只需根据当前股票代码在字典中找到相应的订单列表,并插入订单。我还会在orderstock字典中添加一个条目,将当前订单与适当的列表匹配。
要查找最佳价格,我会在字典中查找当前股票代码的订单列表,对列表进行排序并打印出最高订单。
删除操作比较棘手。首先,我需要按股票代码查找适当的列表。然后,我需要遍历该股票代码的所有订单,找到与当前订单ID匹配的订单并将其删除。如果当前股票代码有很多订单,则这显然效率低下。这是否是存储此信息的最佳方式?

有些愚蠢,但标准规定在下划线后面要小写。 - Ignacio Soler Garcia
如果当前股票代码有很多订单,那么这显然是低效的。是和不是。这取决于“很多”是什么意思以及您希望多久删除一次订单。如果您每秒钟要删除数百个订单,并且每个股票可以有1,000个订单,那么速度会很慢。但是,如果您只谈论某种股票的几十个订单,并且删除订单不频繁,则“低效性”不是问题。 - Jim Mischel
3
这个为什么不用数据库存储呢?数据库非常适合这种行为... - Telastyn
你需要一次性将所有东西都存储在内存中吗?关系型数据库是用于这类“平均”系统的通常工具。 - dlev
+1 这个问题,因为你非常清晰地阐述了你的需求,表达了你的想法,并提供了一些代码。 :) 很好的问题! - Jordan
最终你不是在寻找一个“A”数据结构。你要寻找的是一种数据结构系统,似乎在某种程度上是应用程序结构。这很好。只是为了强调一下。 - Jordan
3个回答

1
我会添加一个额外的字典,其中包含键=订单ID,值=指向初始股票代码字典中订单的引用。
这将像索引一样运作,并为您提供恒定时间的删除。假设您的订单ID是唯一的,它将映射1:1。只需确保从两个字典中都删除它即可。
如评论中建议的那样,我建议添加一个计算总和所需的附加字典,该字典需要通过股票代码访问。这是在内存和恒定时间访问之间进行权衡。除非内存是问题,否则这似乎比每次需要时计算更有利。
如果您收到新订单,只需更新总和、平均值等即可。只需记住,如果您正在并行处理,则需要一些锁定以确保您没有问题。

1
在同样的方式下,我会添加一个描述竞标状态的类来缓存平均竞标、最高竞标等信息——每次移除/添加竞标时都会更新,并存储当前竞标列表。这样,你的更新速度可以大幅提升。除了使用数据库的其他建议增加了价值但也增加了复杂性,此外,在内存枚举上使用PLINQ可以获得惊人的性能。 - payo
1
@payo 缓存整个交易的最佳价格不错,但缓存每个代码的最佳价格会非常快速地累加,并且在增加的效益方面购买得不多。除非有令人信服的分析器证据表明它有帮助,否则我会避免使用它。 - Servy
@Servy 当然,这取决于使用情况。就像是否将计算字段存储在数据库中一样。或者要去规范化的程度等等。 - Jordan
@payo 如果缓存在这里有益处,我会非常惊讶。这就是为什么我提出了分析的原因。如果没有充分的证据,我会有信心认为这是不值得的。特别是如果您像我建议的那样使用SortedSet,因为以这种方式获取派生数据是如此快速/简单,所以您节省的时间非常少。 - Servy
同时@payo “我需要在添加或删除订单后找出哪个订单提供了最优价格。” 当然,这也可以存储在一个类中。 “我需要对所有与特定股票相关的订单执行多个操作,例如获取股票代码为“abc”的订单数量总和。” 因此,给定股票代码的总和(等等)字典。 - Jordan
显示剩余4条评论

1

如果你要处理大量的数据,最好将其放入数据库中。这不是在类中处理的事情。

然而,如果你只使用少量的数据,可以使用 LINQ 在代码中完成。

我认为你应该让 Order 实现 IEnumerable 接口,然后使用 List<Order> 存储你的订单。将 StockCode 设为 Order 的公共属性,然后你就可以使用 Linq 检索订单:

List<Order> orders = GetOrderList();

var ibmOrders = from o in orders
    where o.StockCode == "IBM"
    select o;

从列表中删除项目非常简单:

List<Order> orders = GetOrderList();

var orderToRemove = (from o in orders
  where o.ExchangeId == 1315
  select o).FirstOrDefault();

if (orderToRemove != null) {
    orders.Remove(orderToRemove);
}

使用 Linq 按最佳价格查找非常不错:

Order bestPricedOrder = (from o in orders 
        orderby Price 
        select o).FirstOrDefault(); 

欲了解更多精彩的LINQ技巧,请参阅101 LINQ实例


Linq中的最小/最大值都是O(n)。如果对象数量较多,访问频率高等,则这不是一个有效的选项。它也不比OP的建议更好。此外,从我的阅读中可以看出,“Order”是单数形式。您需要为订单集合创建一个新类。OP使用了List。添加/删除订单列表也将比Dictionary添加/删除要糟糕得多。 - Servy
好想法,Servy。我没有看到 OP 打算使用多少对象,所以我认为 LINQ 是适用于小数据集的建议。我也认为 LINQ 会导致更易读的代码(可维护性),因此比原始方法更好。 - Paul Oliver
1
OP使用的所有数据结构都实现了IEnumerable,因此您仍然可以使用LINQ。在这方面,您的代码没有任何改进。另外,如果有人问:“有没有更高效的方法来做到这一点”,而您认为性能不是问题,只需说出来,让他们做任何事情,而不是建议明显性能较差的东西。我同意性能可能不是问题,但如果OP说它是,即使我质疑其有效性,我也会相应地回答。 - Servy
最佳方式并不总是最高效的方式。这就是为什么解释性语言如今非常流行的原因。有时候,最好的方式是最容易阅读和维护的方式。顺便说一下,我没有重写Orders类,我只是展示了OP如何使用LINQ来完成他所寻找的内容。我不确定你为什么会说“我的代码在这方面没有任何改进”,然后建议他仍然可以使用LINQ。 - Paul Oliver
OP的代码将Order视为单个值,而不是多个值。然后他有一个Order类所代表的组的List,并且有一个Dictionary来收集所有这些(您使用了List)。DictionaryList都实现了IEnumerable,因此可以在您的数据结构上执行任何可执行于OP(或我的)的Linq查询。其中几个操作OP说是最常见的,可以使用这些类的非LINQ方法更有效地完成。特别是添加、删除、查找最小/最大值和搜索。 - Servy
显示剩余2条评论

0

我同意评论中的观点,数据库应该是最好的选择;它们是为这种类型的事情而设计的。

如果您需要在内存中保存此数据,并且确实有许多订单代码,则我会选择 Dictionary<string,SortedSet<Order>>。SortedSet 将使查找最小/最大值变得容易,并且可以快速插入/移除。


如果您需要持久性、事务处理等功能,那么数据库是不二选择。虽然内存解决方案速度可以相当快(显然),但根据操作者的需求而定,也可能并不理想(我认为,这里需要持久性和事务处理)。也许操作者打算永远不关闭计算机或遇到崩溃情况,数据量过大时包含热内存交换等技术可以帮助解决问题:D - Jordan
我想,以asp.net会话为例。根据您的需求,它们支持内存集、状态服务器和数据库选项。 - Jordan

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接