我最近遇到了一个场景,我需要检查IEnumerable<T>
是否以IEnumerable<T>
前缀开头。我搜索并没有找到现有的StackOverflow答案,因此我决定以下面的答案形式提供我自己的解决方案。
答案 0 :(得分:6)
您的扩展程序没有问题,但您可以使用现有的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
,则不会评估所有内容。
答案 1 :(得分:1)
这是一种LINQ风格的扩展方法。我允许您传入自定义相等比较器,从而使我的实现变得灵活:例如,如果您希望new[] { "SOME", "IMPORTANT", "WORDS" }.StartsWith(new[] { "some", "important" })
为真,则可以在StringComparer.OrdinalIgnoreCase
参数之后添加prefix
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;
}
}
}
}
答案 2 :(得分:0)
bool result = longerList.Take(shorterList.Count).SequenceEqual(shorterList);
您还可以将比较方法添加到SequenceEqual:
bool result = longerList.Take(shorterList.Count).SequenceEqual(shorterList, new MyComparer<string>);