Linq Where声明表现缓慢

Rou*_*ace 1 c# linq

我有一个ListObjects(约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秒 - 当然比我更舒服)并且想知道是否有更快的方法来实现这一点.

这段代码只会被使用一次所以不是真正的正常用法,通常我会因为这个原因而忽略它,但是为了学习目的而想知道.

lc.*_*lc. 8

这就是我要做的事情(未经测试,但希望你能得到这个想法):

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).


Ser*_*rvy 7

使用通过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)时间它采取你的方法.