首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何根据属性对超过一百万个项目进行快速分组

如何根据属性对超过一百万个项目进行快速分组
EN

Stack Overflow用户
提问于 2020-03-02 08:57:53
回答 2查看 90关注 0票数 2

我构建了一个程序来解析Fix消息列表,并将它们存储为引用消息。这些修复消息的形式是超过1.5 in的压缩文本文件。

代码语言:javascript
复制
public class Contract
{
    public string ExchangeId { get; set; } = "?";
    public string ExchangeSymbol { get; set; } // Setting this property in my code.
    // I also group Quote by this property below in my dictionary, see below.
}


public class Quote
{
   public Contract Contract = new Contract();
   public decimal Ask = 0M;
   public decimal Bid = 0M;
   // ...
}

public class QuoteMessage
{
   public List<Quote> Quotes = new List<Quote>();
   // ...
}

每个QuoteMessage可以有多个引号。我将它们存储在List<QuoteMessage>中。在这个列表生成之后,我需要根据他们的合同存储报价(而不是报价消息)来分析它们。为此,我运行一个SelectMany并从每个QuoteMessage中提取一个引号列表,将它们输入到Dictionary<Contract, List<Quote>>字典中。在初始化字典时,我要确保有合适的IComparable<Contract>

问题是,列表中的每个元素几乎需要半个小时才能遍历,并将它们插入字典中:

代码语言:javascript
复制
public Dictionary<Contract, List<Quote>> SortQuoteByContract(List<Quote> quotes)
{
    var contractDict = new Dictionary<Contract, List<Quote>>(new IComparable<Contract>());
    foreach (Quote quote in quotes)
    {
        if (!contractDict.ContainsKey(quote.Contract))
        {
            contractDict[quote.Contract] = new List<Quote>();
        }
        contractDict[quote.Contract] = quote; // Line A

    return contractDict;
}

有没有办法加快速度呢?据我所知,我并没有创建引用本身的任何副本(在A行上),只是在<Contract, List<Quote>>字典中存储了一个指向其在内存中位置的指针。这是正确的吗?我想让这个分组尽可能快。一旦报价按合同分组,我就可以在几秒钟内对所有报价进行分析。

谢谢!

EN

回答 2

Stack Overflow用户

发布于 2020-03-02 09:43:25

如果你正在寻找优化,你应该找到发生内存分配的地方。在您的情况下,每次创建新列表时都会发生分配,并且每次向列表中添加项目时都可能发生分配。

采取另一种完全不使用字典的方法:按约定对列表进行排序,然后遍历列表。

假设您有一个单独的批处理处理器类:

代码语言:javascript
复制
interface IContractBatchProcessor
{
     void OnContractStart(Contract contract);
     void ProcessQuote(Quote quote);
     void OnContractEnd()
}

现在,您可以像这样处理列表:

代码语言:javascript
复制
static int CompareByContract(Quote q1, Quote q2) 
{
    // TODO
}

void Process(List<Quote> quote, IContractBatchProcessor processor)
{
    list.Sort(CompareByContract);
    Contract lastContract = null;
    foreach(var quote in list)
    {
        if(quote.Contract != lastContract)
        {
            if(lastContract != null)
            {
                processor.OnContractEnd();
            }
            processor.OnContractStart(quote.Contract);
            lastContract = quote.Contract;
        }
        processor.ProcessQuote(quote);
    }
    processor.OnContractEnd();
}

这是在运行接受委托作为参数的List.Sort method

这种方法会更快,因为您正在执行列表的就地排序,因此没有额外的内存分配。

票数 0
EN

Stack Overflow用户

发布于 2020-03-02 11:06:17

使用PLINQToLookup的代码肯定会比您当前的代码更快。它也很容易阅读,而且从方法使用者的角度来看,也很容易使用。

它将要求您在Contract类中覆盖EqualsGetHashCode,或者编写一个实现IComparer<Contract>的类,该类只是EqualsGetHashCode的外部接口。

代码语言:javascript
复制
public ILookup<Contract, Quote> SortQuoteByContract(List<Quote> quotes) =>
    quotes.AsParallel().ToLookup(_ => _.Contract);

public ILookup<Contract, Quote> SortQuoteByContract(List<Quote> quotes) =>
    quotes.AsParallel().ToLookup(_ => _.Contract, new ContractComparer());
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/60481258

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档