优化LINQ效率

时间:2018-07-05 17:43:47

标签: c# performance linq

我知道了这个问题:

return ngrms.GroupBy(x => x)
            .Select(s => new { Text = s.Key, Count = s.Count() })    
            .Where(x => x.Count > minCount)
            .OrderByDescending(x => x.Count)
            .ToDictionary(g => g.Text, g => g.Count);

ngrms是IEnumerable<String>

有没有一种方法可以优化此代码? 我不在乎是否必须重写所有代码并进行所有低级调整。

2 个答案:

答案 0 :(得分:3)

如果实现的Dictionary可以递增(模拟多集或袋),则可以比LINQ快约3倍,但是除非您有很多ngrms,否则相差很小。在1000万列表中,LINQ代码在我的PC上花费了不到一秒钟的时间,并且具有大约100个唯一值。如果您的LINQ代码花费时间1,则foreachDictionary<string,int>花费0.85,而这段代码花费0.32。

这是在Dictionary中创建可更新值的类:

public class Ref<T> {
    public T val { get; set; }
    public Ref(T firstVal) => val = firstVal;
    public static implicit operator T(Ref<T> rt) => rt.val;
}

(如果C#允许operator ref T,则可以将ref返回到val属性,并且几乎将Ref<T>视为{{1}类型的左值}。

现在,您可以计算T中每个字符串的出现次数,而每个字符串只需查找一次即可。

Dictionary<string,Ref<int>>

最后,您可以通过将计数过滤到要保留的计数来计算答案:

var dictCounts = new Dictionary<string, Ref<int>>();
foreach (var s in ngrms) {
    if (dictCounts.TryGetValue(s, out var refn))
        ++refn.val;
    else
        dictCounts.Add(s, new Ref<int>(1));
}

答案 1 :(得分:1)

通过linq查询,您可以考虑使用简单的foreach循环来重写代码,以获得更好的性能,如下所示。执行需要o(n)的时间复杂度:

Dictionary<string, int> dict = new Dictionary<string, int>();
foreach(var s in ngrms)
{
    if (dict.ContainsKey(s))
        dict[s]++;
    else
        dict.Add(s, 1);
}
return dict.Where(a => a.Value > minCount);