我有一个ListObjects(大约100k),必须迭代才能生成Dictionary
但是代码执行得非常慢,特别是在一行上

public class Item{
        public int ID;
        public int Secondary_ID;
        public string Text;
        public int Number;
}


数据看起来像(100k行)

ID  | Secondary_ID |      Text       | Number
1   |    1         | "something"     | 3
1   |    1         | "something else"| 7
1   |    1         | "something1"    | 4
1   |    2         | "something2"    | 344
2   |    3         | "something3"    | 74
2   |    3         | "something4"    | 1


我希望完成后看起来像这样。 (老实说,任何收藏都可以)

 Dictionary<int, string>

Key             | Value
(secondary_ID)  | (Text : Number)

1               | "Something : 3, Something else : 7, Something1 : 4"
2               | "Something2 : 344"
3               | "Something3 : 74, Something4 : 1"


我的代码当前的工作方式如下:ListAll包含所有数据。

var Final=new Dictionary<int, string>();
var id1s=ListAll.Select(x => x.ID).Distinct().ToList();

foreach(var id1 in id1s) {
    var shortList=ListAll.Where(x => x.ID==id1).ToList(); //99% of time spent is here
    var id2s=shortList.Select(x => x.Secondary_ID).Distinct().ToList();

    foreach(var id2 in id2s) {
        var s=new StringBuilder();
        var items=shortList.Where(x => x.Secondary_ID==id2).ToList();

        foreach(var i in items) {
            s.Append(String.Format("{0} : {1}", i.Text, i.Number));
        }

        Final.Add(id2, s.ToString());
    }
}

return Final;


现在输出是正确的,但是如上面的注释所述,这花费了非常长的时间(90秒-肯定比我满意的多),并且想知道是否有更快的方法来实现。

该代码仅会使用一次,因此实际上并不是正常用法,因此我通常会忽略该原因,但出于学习目的而感到疑惑。

最佳答案

按ID对项目进行分组的一种更有效(甚至更容易编写)的方法是使用GroupBy

var query = ListAll.GroupBy(x => x.Secondary_ID)
    .ToDictionary(group => group.Key,
        group => string.Join(", ",
             group.Select(item => string.Format("{0} : {1}",item.Text , item.Number))),
    //consider refactoring part of this line out to another method
    });


由于您的代码如此之慢的原因,您正在整个列表中搜索每个不同的ID。那是一个O(n ^ 2)运算。 GroupBy不这样做。它在内部根据您要分组的内容使用基于哈希的结构,因此它可以快速(在O(1)时间内)找到任何给定项目所属的存储桶,而不是在O(n)时间内用你的方法。

10-06 08:18