我有一个List的Objects(约10万),即必须以产生在迭代Dictionary.但是代码执行速度非常慢,特别是在一行上
public class Item{
public int ID;
public int Secondary_ID;
public string Text;
public int Number;
}
Run Code Online (Sandbox Code Playgroud)
数据看起来像(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
Run Code Online (Sandbox Code Playgroud)
我希望它在完成后看起来像这样.(任何收藏都要诚实)
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"
Run Code Online (Sandbox Code Playgroud)
我的代码目前的工作方式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;
Run Code Online (Sandbox Code Playgroud)
现在输出是正确的,但是如上面的评论中所述,这需要非常长的时间来处理(90秒 - 当然比我更舒服)并且想知道是否有更快的方法来实现这一点.
这段代码只会被使用一次所以不是真正的正常用法,通常我会因为这个原因而忽略它,但是为了学习目的而想知道.
这就是我要做的事情(未经测试,但希望你能得到这个想法):
var final = ListAll.GroupBy(x => x.Secondary_ID)
.ToDictionary(x => x.Key, x => String.Join(", ",
x.Select(y => String.Format("{0} : {1}",
y.Text, y.Number)))
Run Code Online (Sandbox Code Playgroud)
首先通过Secondary_ID使用GroupBy,然后将结果放入字典中使用ToDictionary.
该GroupBy会将您的数据分组到以下组:
Key = 1: ID | Secondary_ID | Text | Number 1 | 1 | "something" | 3 1 | 1 | "something else"| 7 1 | 1 | "something1" | 4 Key = 2: ID | Secondary_ID | Text | Number 1 | 2 | "something2" | 344 Key = 3: ID | Secondary_ID | Text | Number 2 | 3 | "something3" | 74 2 | 3 | "something4" | 1
然后.ToDictionary方法:
x.Key(我们分组的键,即Secondary_ID).String.Join操作的结果作为值.正在加入的是来自该组内部元素的"Text:Number"的集合 - x.Select(y => String.Format("{0} : {1}", y.Text, y.Number).使用通过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
});
Run Code Online (Sandbox Code Playgroud)
至于你的代码太慢的原因,你在整个列表中搜索每个不同的ID.这是一个O(n ^ 2)操作. GroupBy不这样做.它在内部使用基于散列的结构,基于您正在分组的内容,以便它可以快速(在O(1)时间内)找到任何给定项目所属的存储桶,而不是O(n)时间它采取你的方法.