如何在.NET中检查IEnumerable 是否以另一个IEnumerable 开头?
我最近遇到了一个场景,我需要检查一个IEnumerable<T>
是否以一些IEnumerable<T>
前缀开头。我搜索并没有找到一个现有的StackOverflow答案,所以我决定在下面的答案中提供我自己的解决方案。如何在.NET中检查IEnumerable <T>是否以另一个IEnumerable <T>开头?
这是一种LINQ风格的扩展方法,我通过允许您传入自定义相等比较器来灵活地实现我的实现:例如,如果您希望new[] { "SOME", "IMPORTANT", "WORDS" }.StartsWith(new[] { "some", "important" })
为真,则可以在prefix
参数后面添加StringComparer.OrdinalIgnoreCase
。
public static bool StartsWith<T>(this IEnumerable<T> source, IEnumerable<T> prefix, IEqualityComparer<T> comparer = null)
{
if (source == null)
{
throw new ArgumentNullException(nameof(source));
}
if (prefix == null)
{
throw new ArgumentNullException(nameof(prefix));
}
comparer = comparer ?? EqualityComparer<T>.Default;
using (var sourceEnumerator = source.GetEnumerator())
using (var prefixEnumerator = prefix.GetEnumerator())
{
while (true)
{
if (!sourceEnumerator.MoveNext())
{
return !prefixEnumerator.MoveNext();
}
if (!prefixEnumerator.MoveNext())
{
return true;
}
if (!comparer.Equals(sourceEnumerator.Current, prefixEnumerator.Current))
{
return false;
}
}
}
}
你的扩展是好的,但你可以使用已有的Enumerable.Zip
+ All
:
var longerSeq = new[] { "SOME", "IMPORTANT", "WORDS" };
var shorterSeq = new[] { "some", "important" };
bool startsWithCaseInsensitive = longerSeq
.Zip(shorterSeq, (l, s) => string.Equals(l, s, StringComparison.OrdinalIgnoreCase))
.All(b => b); // are all bools true? Returns false on first false
的方法合并第一序列的每个元素与元素 在第二个序列中具有相同的索引。 如果序列不 没有相同数量的元素,方法合并序列 直到它到达其中一个结束
由于Zip
使用延迟执行它不会评估所有,如果第一已产生了false
。
虽然这不等同于OP解决方案。如果“前缀”序列长于“源”序列,'StartsWith'应该返回'false'。哪个'Zip'实现无法区分。 –
bool result = longerList.Take(shorterList.Count).SequenceEqual(shorterList);
你也可以添加比较方法SequenceEqual:
bool result = longerList.Take(shorterList.Count).SequenceEqual(shorterList, new MyComparer<string>);
请不要使用StackOverflow的您的个人博客。提出一个问题,但不要像这样一次提出问题并回答问题。 – Enigmativity
@Enigmativity我不认为回答我自己的问题有什么问题。这是我遇到的一个真正的问题,其他人也可能遇到。我将与世界其他地方分享我的知识,以便其他开发人员可以快速Google并找到解决方案,而不是浪费时间编写自己的实现。 –
我记得当时看到它被人折磨的地方,但我现在找不到那个参考。那么快乐的日子。去吧。 – Enigmativity