检查字符串是否包含(字符串)列表中的元素

问题描述 投票:0回答:12

对于以下代码块:

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)进行检查。

是否有更好(更高效)的方式来编写这段代码?

c# vb.net list coding-style performance
12个回答
476
投票

使用 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);


12
投票

当你构建你的字符串时,它应该是这样的

bool inact = new string[] { "SUSPENDARE", "DIZOLVARE" }.Any(s=>stare.Contains(s));

6
投票

我喜欢 Marc 的回答,但需要 Contains 匹配为 CaSe InSenSiTiVe。

这是解决方案:

bool b = listOfStrings.Any(s => myString.IndexOf(s, StringComparison.OrdinalIgnoreCase) >= 0))

5
投票

早期的类似问题“Best way to test for existing string against a large list of comparables”中有很多建议。

正则表达式可能足以满足您的要求。该表达式将是所有候选子字符串的串联,它们之间有一个或“

|
”运算符。当然,在构建表达式时,您必须注意未转义的字符,或者由于复杂性或大小限制而导致编译失败。

另一种方法是构建一个 trie 数据结构 来表示所有候选子字符串(这可能会在某种程度上重复正则表达式匹配器正在做的事情)。当您遍历测试字符串中的每个字符时,您将创建一个指向 trie 根的新指针,并将现有指针推进到适当的子节点(如果有的话)。当任何指针到达叶子时,您就会得到匹配。


3
投票

老问题。但是因为

VB.NET
是最初的要求。使用已接受答案的相同值:

listOfStrings.Any(Function(s) myString.Contains(s))

3
投票

因为我需要检查(长)字符串中是否有列表中的项目,所以我得到了这个:

listOfStrings.Any(x => myString.ToUpper().Contains(x.ToUpper()));

或者在 vb.net 中:

listOfStrings.Any(Function(x) myString.ToUpper().Contains(x.ToUpper()))

2
投票

根据您的模式,一项改进是更改为使用 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。


1
投票

你测过速度了吗?

即您是否创建了样本数据集并对其进行了分析?它可能没有你想象的那么糟糕。

这也可能是您可以在单独的线程中产生的东西,并给人以速度的错觉!


1
投票
myList.Any(myString.Contains);

1
投票

Contains
方法的缺点是它不允许指定比较类型,这在比较字符串时通常很重要。它始终区分文化和区分大小写。所以我认为 WhoIsRich 的答案很有价值,我只想展示一个更简单的替代方案:

listOfStrings.Any(s => s.Equals(myString, StringComparison.OrdinalIgnoreCase))

0
投票

如果速度至关重要,您可能需要寻找 Aho-Corasick 算法 来获取模式集。

这是一个带有失败链接的trie,即复杂度为O(n+m+k),其中n是输入文本的长度,m是模式的累积长度,k是匹配的数量。您只需修改算法以在找到第一个匹配项后终止。


0
投票

细微的变化,我需要找出字符串中是否有完整的单词和不区分大小写的。

myString.Split(' ', StringSplitOptions.RemoveEmptyEntries).Intersect(listOfStrings).Any())

不区分大小写

myString
listOfStrings
已转换为大写。

© www.soinside.com 2019 - 2024. All rights reserved.