带有谓词和结果限制的 c# Enumerable Take 方法
c# Enumerable Take method with predicate and result limit
在 C# 中是否有用于 IEnumerable 的扩展方法可以 return 带有谓词的集合中的项目,直到达到某个给定的限制?
例如:
string[] source = { "zero", "one", "two", "three", "four", "five", "six", "seven", "eight", "nine" };
var result = source.Take(2, item => item.EndsWith("e"));
// result == { "one", "three" }
这个例子很简单地反映了这个想法,但对于更复杂的逻辑它可能很有用,而不是评估集合中的每个项目。
我想出了以下解决方案,但也许 .NET 中已经有类似的东西了。
请勿使用以下代码 - 仅供参考
public static IEnumerable<T> Take<T>(this IEnumerable<T> enumerable,
int count,
Func<T, bool> predicate)
{
if (enumerable == null)
{
yield break;
}
using (IEnumerator<T> iterator = enumerable.GetEnumerator())
{
var matchingCount = 0;
while (matchingCount < count && iterator.MoveNext())
{
if (predicate(iterator.Current))
{
matchingCount++;
yield return iterator.Current;
}
}
}
}
更新
优雅的解决方案 - 这会做同样的事情:
public static IEnumerable<T> Take<T>(this IEnumerable<T> enumerable,
int count,
Func<T, bool> predicate)
{
return enumerable.Where(predicate).Take(count);
}
所以通过执行下面的代码:
string[] source = { "zero", "one", "two", "three", "four", "five", "six", "seven", "eight", "nine" };
var result = source
.Where(n => {
Console.WriteLine("processing " + n);
return n.EndsWith("e");
})
.Take(2)
.ToList();
控制台中将记录以下内容:
processing one
processing three
希望这对以后的任何人都有帮助。
记住人们:不要重新发明轮子。
您可以组合 Take
和 Where
:
var result = source.Where(item => item.Contains("e")).Take(2);
Where
while 将过滤集合,Take
将在找到 2 个元素后停止迭代。由于 Where
和 Take
都是惰性的,因此在迭代之前不会创建集合,就像您的解决方案一样,可能会有性能损失,因为我们有两个 LINQ 运算符,但在大多数情况下,这不应该是一个问题。
有:
var results = source.Where(predicate).Take(limit);
在 C# 中是否有用于 IEnumerable 的扩展方法可以 return 带有谓词的集合中的项目,直到达到某个给定的限制?
例如:
string[] source = { "zero", "one", "two", "three", "four", "five", "six", "seven", "eight", "nine" };
var result = source.Take(2, item => item.EndsWith("e"));
// result == { "one", "three" }
这个例子很简单地反映了这个想法,但对于更复杂的逻辑它可能很有用,而不是评估集合中的每个项目。
我想出了以下解决方案,但也许 .NET 中已经有类似的东西了。
请勿使用以下代码 - 仅供参考
public static IEnumerable<T> Take<T>(this IEnumerable<T> enumerable,
int count,
Func<T, bool> predicate)
{
if (enumerable == null)
{
yield break;
}
using (IEnumerator<T> iterator = enumerable.GetEnumerator())
{
var matchingCount = 0;
while (matchingCount < count && iterator.MoveNext())
{
if (predicate(iterator.Current))
{
matchingCount++;
yield return iterator.Current;
}
}
}
}
更新
优雅的解决方案 - 这会做同样的事情:
public static IEnumerable<T> Take<T>(this IEnumerable<T> enumerable,
int count,
Func<T, bool> predicate)
{
return enumerable.Where(predicate).Take(count);
}
所以通过执行下面的代码:
string[] source = { "zero", "one", "two", "three", "four", "five", "six", "seven", "eight", "nine" };
var result = source
.Where(n => {
Console.WriteLine("processing " + n);
return n.EndsWith("e");
})
.Take(2)
.ToList();
控制台中将记录以下内容:
processing one
processing three
希望这对以后的任何人都有帮助。
记住人们:不要重新发明轮子。
您可以组合 Take
和 Where
:
var result = source.Where(item => item.Contains("e")).Take(2);
Where
while 将过滤集合,Take
将在找到 2 个元素后停止迭代。由于 Where
和 Take
都是惰性的,因此在迭代之前不会创建集合,就像您的解决方案一样,可能会有性能损失,因为我们有两个 LINQ 运算符,但在大多数情况下,这不应该是一个问题。
有:
var results = source.Where(predicate).Take(limit);