[英]c# need help optimizing string array function
下面的代码在较小的数据集上运行良好。 但是,GetMatchCount和BuildMatchArrary在大型结果上非常缓慢。 任何人都可以推荐任何其他方法来节省处理时间吗? 将数组写入文件会更好吗? 列表通常只是速度慢而不是最佳选择吗?
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
public class Client
{
public int Id;
public string FirstName
{
get
{
var firstName = //<call to get from database via Id>
return firstName;
}
}
public string MiddleName
{
get
{
var middleName = //<call to get from database via Id>
return middleName;
}
}
public string LastName
{
get
{
var lastName = //<call to get from database via Id>
return lastName;
}
}
public string FullName
{
get
{
return FirstName + " " + MiddleName + " " + LastName;
}
}
public int GetMatchCount(IEnumerable<string> clientFirstNames, IEnumerable<string> clientMiddleNames, IEnumerable<string> clientLastNames)
{
var clientFullNames = BuildMatchArray(clientFirstNames, clientMiddleNames, clientLastNames);
return clientFullNames.Count(x => x == FullName);
}
public string[] BuildMatchArray(IEnumerable<string> clientFirstNames, IEnumerable<string> clientMiddleNames, IEnumerable<string> clientLastNames)
{
Debug.Assert(clientFirstNames.Count() == clientMiddleNames.Count() && clientMiddleNames.Count() == clientLastNames.Count());
var clientFullNames = new List<string>();
for (int i = 0; i < clientFirstNames.Count(); i++)
{
clientFullNames.Add(clientFirstNames.ElementAt(i) + " " + clientMiddleNames.ElementAt(i) + " " + clientLastNames.ElementAt(i));
}
return clientFullNames.ToArray();
}
}
您在哪里得到这些琴弦? 如果您使用的是惰性序列,则每次调用Count()
,都必须迭代整个序列以计算序列中有多少个对象。 如果IEnumerable<T>
确实是T[]
或List<T>
,则Count()
被优化为仅调用Length
或Count
属性,这并不昂贵。 同样, ElementAt
效率也很低,并且会迭代集合。 因此,对于内存中的惰性序列,此性能将很差,但是如果您从SQL或外部源流式传输结果,则它的确会很差,甚至可能不正确。
BuildMatchArray
性能更高的实现将是这样的:
public IEnumerable<string> ZipNames(IEnumerable<string> firsts,
IEnumerable<string> middles, IEnumerable<string> lasts)
{
using(var e1 = firsts.GetEnumerator())
using(var e2 = middles.GetEnumerator())
using(var e3 = lasts.GetEnumerator())
{
var stop = false;
while (!stop)
{
var hasNext1 = e1.MoveNext();
var hasNext2 = e2.MoveNext();
var hasNext3 = e3.MoveNext();
if (hasNext1 && hasNext2 && hasNext3)
{
yield return $"{e1.Current} {e2.Current} {e3.Current}";
}
else
{
stop = true;
Debug.Assert(!(hasNext1 || hasNext2 || hasNext3));
}
}
}
}
这只需要每个输入集合一次迭代,并且不需要将元素复制到新的List<T>
。 还要注意的另一点是, List<T>
以4个元素的容量开始,并且当它填满时,它将所有元素复制到具有两倍容量的新列表中。 因此,如果序列很大,您将复制很多次。
此实现与System.Linq.Enumerable.Zip
非常相似
就您而言,您也不应该对序列执行ToArray
。 这将需要再次复制,并且可能是一个巨大的数组。 如果仅将该数组发送到.Count(x => x == y)
,则保持惰性IEnumerable
会更好,因为Count
懒惰地对惰性序列进行操作并按其所看到的那样对数据进行流式传输和计数,从未如此要求将完整的集合存储在内存中。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.