当前位置: 首页 > 编程语言 > C#

使用Linq在IEnumerable 中查找序列分享

时间:2023-04-10 19:52:41 C#

C#学习教程:使用Linq在IEnumerable中查找序列允许以下调用:intstartIndex=largeSequence.FindSequence(subSequence)匹配项必须是连续且有序的。这是在序列中查找子序列的算法的实现。我调用了方法IndexOfSequence,因为它使intent更明确,而且类似于现有的IndexOf方法:);}publicstaticintIndexOfSequence(这个IEnumerable源,IEnumerable序列,IEqualityComparer比较器){varseq=sequence.ToArray();诠释p=0;//源序列中的当前位置inti=0;//搜索序列中的当前位置varprospects=newList();//预期匹配列表foreach(variteminsource){//删除不良预期匹配prospects.RemoveAll(k=>!comparer.Equals(item,seq[p-k]));//是否是预期匹配的开始?if(comparer.Equals(item,seq[0])){prospects.Add(p);}//当前字符是否继续部分匹配?if(comparer.Equals(item,seq[i])){i++;//我们有完全匹配吗?if(i==seq.Length){//宾果!返回p-seq.Leng第1次;}}else//不匹配{//我们是否有预期的匹配可以回退?if(prospects.Count>0){//是的,使用第一个intk=prospects[0];我=p-k+1;}else{//否,从搜索序列的开头开始i=0;}}p++;}//不匹配返回-1;我没有完全测试它所以它可能仍然包含错误我只是对众所周知的角落案例进行了一些测试以确保我没有陷入明显的陷阱。到目前为止似乎工作正常......我认为复杂度接近O(n),但我不是大O表示法的专家,所以我可能是错的......至少它只枚举了源序列反正曾经一次,所以应该是合理有效的。您希望能够使用的代码不是LINQ,所以我不明白为什么需要使用LINQ来实现它。这与子字符串搜索基本上是相同的问题(实际上,顺序很重要的枚举是“字符串”的概括)。由于计算机科学长期以来经常考虑这个问题,所以您站在巨人的肩膀上。一些合理的起点是:http://en.wikipedia.org/wiki/Knuth%E2%80%93Morris%E2%80%93Pratt_algorithmhttp://en.wikipedia.org/wiki/Boyer%E2%80%93Moore_string_search_algorithmhttp://en.wikipedia.org/wiki/Rabin-karp即使只是维基百科文章中的伪代码也足以轻松移植到C#。查看不同情况下的性能描述,确定您的代码最有可能遇到哪些情况。我知道这是一个老问题,但我需要这个正确的方法,我这样写了:publicstaticintContainsSubsequence(thisIEnumerableelements,IEnumerablesubSequence)whereT:IEquatable{returnContainsSubsequence(elements,0,subSequence);}privatestaticintContainsSubsequence(IEnumerableelements,intindex,IEnumerablesubSequence)whereT:IEquatable{//我们还有剩余的元素吗?boolelementsLeft=elements.Any();//我们还有剩余的子序列吗?boolsequenceLeft=subSequence.Any();//没有元素但子序列不完全匹配if(!elementsLeft&&sequenceLeft)return-1;//不,没有匹配//没有子序列的元素,这意味着即使有更多的元素//我们也完全匹配了子序列if(!sequenceLeft)returnindex-subSequence.Count();//匹配!//如果我们没有达到终止条件,//根据第一个元素检查子序列的第一个元素if(subSequence.First().Equals(e.First()))//是的,它匹配-移动e到下一个。在每个返回中消耗(跳过)一个元素ContainsSubsequence(elements.Skip(1),index+1subSequence.Skip(1));else//不,它不匹配。尝试下一个元素,不消耗子序列中的元素//returnContainsSubsequence(elements.Skip(1),index+1,subSequence);更新为不仅返回子序列匹配,而且从原始序列开始,这是一个IEnumerable完全惰性的扩展方法,提前终止,并且比当前投票最高的答案更有效。然而,正如@wai-ha-lee指出的那样,它是递归的并创建了很多枚举器。在适用的地方使用它(性能/内存)。这可以满足我的需要,但是YMMV。更新:鉴于问题的澄清,我在下面的回复不适用。离开它是出于历史目的。您可能想使用mySequence.Where()。那么关键是优化谓词以在您的环境中正常工作。根据您的要求和典型的使用模式,这可能会有很大差异。对小集合有用的东西很可能对大集合也有用,这取决于T的类型。当然,如果你90%的使用都是针对小集合的,那么为大集合优化异常值似乎有点YAGNI。您可以使用这个名为Sequences的库来执行此操作(免责声明:我是作者)。它有一个IndexOfSlice方法可以完全满足您的需求-它是Knuth-Morris-Pratt算法的实现。以上就是C#学习教程:使用Linq查找IEnumerable中序列分享的所有内容。如果对大家有用,需要详细了解C#学习教程,希望大家多多关注——intstartIndex=largeSequence.AsSequence().IndexOfSlice(subSequence);本文收集自网络,不代表立场。如涉及侵权,请点击右侧联系管理员删除。如需转载请注明出处: