String.comparison 性能(带修剪)
我需要进行大量高性能的不区分大小写的字符串比较,并意识到我的做法 .ToLower().Trim() 真的很愚蠢,因为所有新字符串都被分配了
所以我挖了一点,这样似乎更可取:
String.Compare(txt1,txt2, StringComparison.OrdinalIgnoreCase)
这里唯一的问题是我想忽略前导或尾随空格,即 Trim() 但如果我使用 Trim,我在字符串分配方面也会遇到同样的问题。我想我可以检查每个字符串,看看它是否 StartsWith(" ") 或 EndsWith(" "),然后再修剪。要么找出索引,每个字符串的长度并传递给 string.Compare override
public static int Compare
(
string strA,
int indexA,
string strB,
int indexB,
int length,
StringComparison comparisonType
)
但这看起来相当混乱,如果我不为尾随和的每个组合创建一个非常大的 if-else 语句,我可能必须使用一些整数两个字符串上都有前导空白...那么有什么优雅的解决方案的想法吗?
这是我目前的建议:
public bool IsEqual(string a, string b)
{
return (string.Compare(a, b, StringComparison.OrdinalIgnoreCase) == 0);
}
public bool IsTrimEqual(string a, string b)
{
if (Math.Abs(a.Length- b.Length) > 2 ) // if length differs by more than 2, cant be equal
{
return false;
}
else if (IsEqual(a,b))
{
return true;
}
else
{
return (string.Compare(a.Trim(), b.Trim(), StringComparison.OrdinalIgnoreCase) == 0);
}
}
I need to do alot of high-performance case-insensitive string comparisons and realized that my way of doing it .ToLower().Trim() was really stupid due do all the new strings being allocated
So I digged around a little and this way seems preferable:
String.Compare(txt1,txt2, StringComparison.OrdinalIgnoreCase)
The only problem here is that I want to ignore leading or trailing spaces, ie Trim() but if I use Trim I have the same problem with string allocations. I guess I could check each string and see if it StartsWith(" ") or EndsWith(" ") and only then Trim. Either that or figure out the index,length for each string and pass to string.Compare override
public static int Compare
(
string strA,
int indexA,
string strB,
int indexB,
int length,
StringComparison comparisonType
)
but that seems rather messy and I probably have to to use some integers if I dont make a really big if-else statement for every combination of trailing and leading blanks on both strings... so any ideas of an elegant solution?
Here's my current proposal:
public bool IsEqual(string a, string b)
{
return (string.Compare(a, b, StringComparison.OrdinalIgnoreCase) == 0);
}
public bool IsTrimEqual(string a, string b)
{
if (Math.Abs(a.Length- b.Length) > 2 ) // if length differs by more than 2, cant be equal
{
return false;
}
else if (IsEqual(a,b))
{
return true;
}
else
{
return (string.Compare(a.Trim(), b.Trim(), StringComparison.OrdinalIgnoreCase) == 0);
}
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(9)
像这样的事情应该可以做到:
示例:
输出:
您应该根据简单的修剪和比较一些真实数据来分析它,看看您将要使用它的用途是否真的有任何差异。
Something like this should do it:
Example:
Output:
You should profile it against a simple Trim and Compare with some real data, to see if there really is any difference for what you are going to use it for.
我将使用您拥有的代码
并根据需要添加任何
.Trim()
调用。这将在大多数情况下保存初始选项 4 个字符串 (.ToLower().Trim()
),并始终保存两个字符串 (.ToLower()
)。如果您在此之后遇到性能问题,那么您的“混乱”选项可能是最好的选择。
I would use the code you have
and add any
.Trim()
calls as you need them. This will save your initial option 4 strings most of the time (.ToLower().Trim()
, and two strings all of the time (.ToLower()
).If you are suffering performance problems after this, then your "messy" option is likely the best bet.
首先确保您确实需要优化此代码。也许创建字符串的副本不会明显影响您的程序。
如果你确实需要优化,你可以尝试在第一次存储字符串时处理它们,而不是在比较它们时处理它们(假设它发生在程序的不同阶段)。例如,存储字符串的修剪和小写版本,以便在比较它们时可以简单地检查等效性。
First make sure that you really need to optimize this code. Maybe creating copies of the strings won't noticeably affect your program.
If you really need to optimize, you can try to process the strings when you first store them instead of when you compare them (assuming it happens in different stages of the program). For example, store trimmed and lowercase versions of the strings, so that when you compare them you can use simply check for equivalence.
难道你不能只修剪(并可能使其小写)每个字符串一次(在获取它时)吗?做更多的事情听起来像是过早的优化......
Can't you just trim (and possibly make it lowercase) each string exactly once (when obtaining it)? Doing more sounds like premature optimization....
我注意到您的第一个建议仅比较相等而不是排序,这可以进一步节省效率。
当然,如果没有匹配的哈希码生成器,什么是相等检查器:
I notice that your first suggestion only compares for equality rather than sorting, that allows some further efficiency savings.
Of course, what is an equality checker without a matching hashcode producer:
使用现代版本的 .NET 和
Span
现在可以很容易地做到这一点,而不会牺牲性能:上面比较两个字符串是否相等,但可以通过使用 CompareTo() 而不是 < a href="https://learn.microsoft.com/en-us/dotnet/api/system.memoryextensions.equals?view=net-7.0" rel="nofollow noreferrer">Equals()。
With modern versions of .NET and
Span<char>
this is now very easy to do without sacrificing performance:The above compares two strings for equality, but can easily be used for ordering of strings by using CompareTo() instead of Equals().
问题是,如果需要做,就需要做。我认为您的任何不同解决方案都不会产生影响。在每种情况下都需要进行多次比较才能找到空白或将其删除。
显然,删除空格是问题的一部分,因此您不必担心这一点。
如果您使用 unicode 字符并且可能比复制字符串慢,那么在比较之前将字符串小写是一个错误。
The thing is, if it needs to be done, it needs to be done. I don't think that any of your different solutions will make a difference. In each case there needs to be a number of comparisons to find the whitespace or removing it.
Apparently, removing whitespace is part of the problem, so you shouldn't worry about that.
And lowercasing a string before comparing, is a bug if your working with unicode characters and possibly slower than copying a string.
关于过早优化的警告是正确的,但我假设您已经对此进行了测试,并发现大量时间被浪费在复制字符串上。在这种情况下,我会尝试以下操作:
FindStartAndLength 是一个函数,用于查找“修剪”字符串的起始索引和长度(这是未经测试的,但应该给出总体思路):
The warnings are about premature optimization are correct, but I'll assume you've tested this and found that a lot of time is being wasted copying strings. In that case I would try the following:
FindStartAndLength is a function that finds the starting index and length of the "trimmed" string (this is untested but should give the general idea):
您可以实现自己的
StringComparer
。这是一个基本的实现:备注:
Trim
和ToLower
更好You could implement your own
StringComparer
. Here's a basic implementation :Remarks :
Trim
andToLower
anyway)GetHashCode
method is not implemented, so don't use it as a key in a dictionary