【问题标题】:What is the best C# Data Structure(s) For the Following Situation以下情况的最佳 C# 数据结构是什么
【发布时间】:2012-04-13 23:12:25
【问题描述】:

我的申请要求如下。我需要存储如下所示的订单:

  • 每个订单都与特定的股票代码(字符串)相关,并具有与其相关的价格、数量以及是否被买卖(布尔值)。

  • 我需要对与特定股票相关的所有订单执行多项操作,例如获取股票代码“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 匹配的订单并将其删除。如果当前股票代码有很多订单,这显然是低效的。这是存储这些信息的最佳方式吗?

【问题讨论】:

  • 有些愚蠢,但标准规定 _ 后变为小写。
  • "如果当前股票代码有很多订单,这显然是低效的。"是和不是。这取决于“很多”是什么以及您希望删除订单的频率。如果您每秒删除数百个订单,而每只股票可以有 1,000 个订单,那么速度会很慢。但是,如果您正在谈论一个股票的几十个订单并且删除一个订单并不常见,那么“效率低下”不是问题。
  • 有什么理由不在数据库中吗?它们是为这种行为量身定做的......
  • 您需要一次将所有内容都保存在内存中吗?关系数据库是用于此类“普通”系统的常用工具。
  • +1 这个问题,因为你清楚地说明了你需要什么,很好地解释了你的想法,并提供了一些代码。 :) 好问题!

标签: c# data-structures


【解决方案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 Samples

【讨论】:

  • Linq 中的最小值/最大值都是 O(n)。如果有相当数量的对象,频繁访问等,这不是一个有效的选择。它也并不比 OPs 的建议更好。此外,Order 在我阅读 OP 时是单数。您需要为订单集合创建一个新类。 OP使用列表。添加/删除到订单列表也会比Dictionary添加/删除差很多。
  • 好主意服务。我没有看到 OP 计划使用多少对象,所以我认为 LINQ 将是对小型数据集的建议。我还认为 LINQ 会导致代码更具可读性(阅读:可维护),因此将是比原始方法更好的解决方案。
  • OP 使用的所有数据结构都实现了IEnumerable,因此您仍然可以使用 LINQ。您的代码在这方面没有任何改进。此外,如果有人问,“有没有更高效的方法来做到这一点”,而您认为性能不是问题,那么直接说出来,让他们做任何事情,而不是建议性能明显降低的东西。我同意性能可能不是问题,但如果 OP 说是问题,即使我质疑有效性,我也会相应地回答。
  • 最好的方式并不总是意味着最好的方式。这就是为什么解释语言如今风靡一时的原因。有时最好的方法是最容易阅读和维护的。顺便说一句,我没有重写 Orders 类,我只是展示了 OP 如何使用 LINQ 来完成他正在寻找的东西。我不确定你为什么说“我的代码在这方面没有任何改进”,然后建议他仍然可以使用 LINQ。
  • OP 的代码将Order 视为单个值,而不是多个值。然后,他有一个ListOrders 代表您的Order 类代表的组,并有一个Dictionary 来收集所有这些(您使用List)。 DictionaryList 都实现了 IEnumerable,因此可以在您的数据结构上执行的任何 Linq 查询都可以在 OP(或我的)上执行。 OP 所说的一些最常见的操作可以使用这些类的非 LINQ 方法更有效地完成。特别是添加、删除、查找最小值/最大值和搜索。
【解决方案2】:

我会添加一个额外的字典,它包含 key = orderid,value = 对股票代码初始字典中列表中订单的引用。

这将像一个索引,并给你不断的时间删除。假设您的订单 ID 不同,它将按 1:1 映射。只需确保从两个字典中删除它即可。

正如 cmets 中所建议的,我会推荐一个额外的字典,其中包含您需要通过股票代码访问的计算总和。这是权衡内存的恒定时间访问。除非内存是一个问题,否则这似乎有利于在您每次需要时计算它。 如果您收到新订单,您只需更新总和、平均值等。请记住,如果您正在并行执行一些操作,则需要一些锁定以确保您没有问题。

【讨论】:

  • PS 转 OP,酷名 Fonzie ;)
  • 以同样的方式,我将添加一个描述出价状态的类,以缓存平均值、最高出价等 - 每次移除/添加出价时都会更新,并将存储当前出价清单。这样,您的更新可能会快很多。使用数据库的所有其他建议增加了价值但复杂性,除了在内存中的枚举上使用 PLINQ 之外,您可以获得令人难以置信的性能。
  • @payo 缓存整个交易的最佳价格不会很糟糕,但是缓存每个代码的最佳价格会很快加起来,并且在额外收益方面几乎没有购买那么多。除非有令人信服的分析器证据,否则我会避免它。
  • 是的,我绝对会将这些东西存储在缓存类中:) 好点! +1 我同意你关于数据库的观点,请参阅我对 Servy 的评论;)这显然有点半开玩笑,但 w/e
  • @Servy 当然,无论哪种方式都可以争论。我同意分析将非常有价值。
【解决方案3】:

我同意 cmets 的观点,即数据库是最佳选择;它们是为这类事情设计的。

如果您需要在内存中保存这些数据,并且每个代码确实有很多订单,那么我会选择Dictionary&lt;string, SortedSet&lt;Order&gt;&gt;。 SortedSet 将使查找最小值/最大值变得容易,以及快速插入/删除。

【讨论】:

  • 如果您需要持久性、事务和类似的东西,数据库是您的最佳选择。根据 OP 的需要,内存中的解决方案可以非常快速(显然)和理想(我承认我也认为需要持久性和事务;))也许 OP 只是计划永远不关闭计算机或让它崩溃;) 当数据变得太大时,包括热内存交换:D
  • 我想作为一个例子可以查看 asp.net 会话。它们支持内存集、状态服务器和数据库选项,具体取决于您的需要。
猜你喜欢
  • 2017-05-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-07-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多