对于以下代码块:
For I = 0 To listOfStrings.Count - 1
If myString.Contains(lstOfStrings.Item(I)) Then
Return True
End If
Next
Return False
输出为:
案例一:
myString: C:\Files\myfile.doc
listOfString: C:\Files\, C:\Files2\
Result: True
案例二:
myString: C:\Files3\myfile.doc
listOfString: C:\Files\, C:\Files2\
Result: False
列表 (listOfStrings) 可能包含多个项目(最少 20 个)并且必须针对数千个字符串(如 myString)进行检查。
是否有更好(更高效)的方式来编写这段代码?
使用 LINQ,并使用 C#(这些天我不太了解 VB):
bool b = listOfStrings.Any(s=>myString.Contains(s));
或(更短、更高效,但可以说不太清楚):
bool b = listOfStrings.Any(myString.Contains);
如果你正在测试相等性,那么值得一看
HashSet
等,但这对部分匹配没有帮助,除非你将它分成片段并添加复杂性的顺序。
更新:如果你真的是指“StartsWith”,那么你可以对列表进行排序并将其放入数组中;然后使用
Array.BinarySearch
查找每个项目 - 通过查找检查它是完全匹配还是部分匹配。
更新:在最近的 .Net 中,Contains 有可选的 StringComparison parameter ,可用于不区分大小写的比较,例如myString.Contains(s,StringComparison.CurrentCultureIgnoreCase);
当你构建你的字符串时,它应该是这样的
bool inact = new string[] { "SUSPENDARE", "DIZOLVARE" }.Any(s=>stare.Contains(s));
我喜欢 Marc 的回答,但需要 Contains 匹配为 CaSe InSenSiTiVe。
这是解决方案:
bool b = listOfStrings.Any(s => myString.IndexOf(s, StringComparison.OrdinalIgnoreCase) >= 0))
早期的类似问题“Best way to test for existing string against a large list of comparables”中有很多建议。
正则表达式可能足以满足您的要求。该表达式将是所有候选子字符串的串联,它们之间有一个或“
|
”运算符。当然,在构建表达式时,您必须注意未转义的字符,或者由于复杂性或大小限制而导致编译失败。
另一种方法是构建一个 trie 数据结构 来表示所有候选子字符串(这可能会在某种程度上重复正则表达式匹配器正在做的事情)。当您遍历测试字符串中的每个字符时,您将创建一个指向 trie 根的新指针,并将现有指针推进到适当的子节点(如果有的话)。当任何指针到达叶子时,您就会得到匹配。
老问题。但是因为
VB.NET
是最初的要求。使用已接受答案的相同值:
listOfStrings.Any(Function(s) myString.Contains(s))
因为我需要检查(长)字符串中是否有列表中的项目,所以我得到了这个:
listOfStrings.Any(x => myString.ToUpper().Contains(x.ToUpper()));
或者在 vb.net 中:
listOfStrings.Any(Function(x) myString.ToUpper().Contains(x.ToUpper()))
根据您的模式,一项改进是更改为使用 StartsWith 而不是 Contains。 StartsWith 只需要遍历每个字符串,直到找到第一个不匹配的字符串,而不必在找到一个字符位置时在每个字符位置重新开始搜索。
此外,根据您的模式,您似乎可以提取 myString 路径的第一部分,然后反转比较——在字符串列表中查找 myString 的起始路径,而不是相反.
string[] pathComponents = myString.Split( Path.DirectorySeparatorChar );
string startPath = pathComponents[0] + Path.DirectorySeparatorChar;
return listOfStrings.Contains( startPath );
编辑:使用 @Marc Gravell 提到的 HashSet 想法会更快,因为您可以将
Contains
更改为 ContainsKey
并且查找将是 O(1) 而不是 O(N)。您必须确保路径完全匹配。请注意,这不是@Marc Gravell 的通用解决方案,而是针对您的示例量身定制的。
抱歉,C# 示例。我还没喝足够的咖啡来翻译成 VB。
你测过速度了吗?
即您是否创建了样本数据集并对其进行了分析?它可能没有你想象的那么糟糕。
这也可能是您可以在单独的线程中产生的东西,并给人以速度的错觉!
myList.Any(myString.Contains);
Contains
方法的缺点是它不允许指定比较类型,这在比较字符串时通常很重要。它始终区分文化和区分大小写。所以我认为 WhoIsRich 的答案很有价值,我只想展示一个更简单的替代方案:
listOfStrings.Any(s => s.Equals(myString, StringComparison.OrdinalIgnoreCase))
如果速度至关重要,您可能需要寻找 Aho-Corasick 算法 来获取模式集。
这是一个带有失败链接的trie,即复杂度为O(n+m+k),其中n是输入文本的长度,m是模式的累积长度,k是匹配的数量。您只需修改算法以在找到第一个匹配项后终止。
细微的变化,我需要找出字符串中是否有完整的单词和不区分大小写的。
myString.Split(' ', StringSplitOptions.RemoveEmptyEntries).Intersect(listOfStrings).Any())
不区分大小写
myString
和listOfStrings
已转换为大写。