Stu*_*etz 13 c# ienumerable .net-4.0 c#-4.0
有时检查不可重复 的内容是否有用,以查看IEnumerable它是否为空.LINQ Any对此不起作用,因为它消耗了序列的第一个元素,例如
if(input.Any())
{
foreach(int i in input)
{
// Will miss the first element for non-repeatable sequences!
}
}
Run Code Online (Sandbox Code Playgroud)
(注意:我知道在这种情况下没有必要进行检查 - 这只是一个例子!真实世界的例子是Zip对一个IEnumerable可能是空的右手执行.如果它是空的,我想要结果是左手IEnumerable原样.)
我想出了一个看起来像这样的潜在解决方案:
private static IEnumerable<T> NullifyIfEmptyHelper<T>(IEnumerator<T> e)
{
using(e)
{
do
{
yield return e.Current;
} while (e.MoveNext());
}
}
public static IEnumerable<T> NullifyIfEmpty<T>(this IEnumerable<T> source)
{
IEnumerator<T> e = source.GetEnumerator();
if(e.MoveNext())
{
return NullifyIfEmptyHelper(e);
}
else
{
e.Dispose();
return null;
}
}
Run Code Online (Sandbox Code Playgroud)
然后可以按如下方式使用:
input = input.NullifyIfEmpty();
if(input != null)
{
foreach(int i in input)
{
// Will include the first element.
}
}
Run Code Online (Sandbox Code Playgroud)
我有两个问题:
1)这是否合理?从性能的角度来看,它可能会出现问题吗?(我猜不是,但值得问.)
2)是否有更好的方法来实现相同的最终目标?
编辑#1:
以下是一个不可重复的例子IEnumerable,以澄清:
private static IEnumerable<int> ReadNumbers()
{
for(;;)
{
int i;
if (int.TryParse(Console.ReadLine(), out i) && i != -1)
{
yield return i;
}
else
{
yield break;
}
}
}
Run Code Online (Sandbox Code Playgroud)
基本上,来自用户输入或流等的东西.
编辑#2:
我需要澄清一点,我正在寻找一种保留懒惰性质的解决方案IEnumerable- 在某些情况下将其转换为列表或数组可以是一个答案,但这不是我在这里所追求的.(现实世界的原因是,IEnumerable在我的情况下,项目中的项目数量可能很大,并且重要的是不要将它们全部存储在内存中.)
小智 2
你不需要把它复杂化。foreach带有一个额外变量的常规循环bool就可以解决问题。
如果你有
if(input.Any())
{
A
foreach(int i in input)
{
B
}
C
}
Run Code Online (Sandbox Code Playgroud)
如果你不想读input两遍,你可以将其更改为
bool seenItem = false;
foreach(int i in input)
{
if (!seenItem)
{
seenItem = true;
A
}
B
}
if (seenItem)
{
C
}
Run Code Online (Sandbox Code Playgroud)
根据具体B情况,您也许可以seenItem完全避免该变量。
在您的情况下,Enumerable.Zip是一个相当基本的函数,很容易重新实现,并且您的替换函数可以使用与上面类似的函数。
编辑:你可能会考虑
public static class MyEnumerableExtensions
{
public static IEnumerable<TFirst> NotReallyZip<TFirst, TSecond>(this IEnumerable<TFirst> first, IEnumerable<TSecond> second, Func<TFirst, TSecond, TFirst> resultSelector)
{
using (var firstEnumerator = first.GetEnumerator())
using (var secondEnumerator = second.GetEnumerator())
{
if (secondEnumerator.MoveNext())
{
if (firstEnumerator.MoveNext())
{
do yield return resultSelector(firstEnumerator.Current, secondEnumerator.Current);
while (firstEnumerator.MoveNext() && secondEnumerator.MoveNext());
}
}
else
{
while (firstEnumerator.MoveNext())
yield return firstEnumerator.Current;
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
433 次 |
| 最近记录: |