C# 我在这里重复这个枚举两次吗?
考虑以下代码块:C# 我在这里重复这个枚举两次吗?,c#,algorithm,optimization,C#,Algorithm,Optimization,考虑以下代码块: using (FileStream fs = new FileStream(@"C:\bad_records.txt", FileMode.Create, FileAccess.Write)) { var badEnumerable = _cache.Where(kvp => !kvp.Value.Item1)
using (FileStream fs = new FileStream(@"C:\bad_records.txt",
FileMode.Create,
FileAccess.Write))
{
var badEnumerable = _cache.Where(kvp => !kvp.Value.Item1);
fs.WriteLine(string.Format("BAD RECORDS ({0})", badEnumerable.Count()));
fs.WriteLine("==========");
foreach (var item in badEnumerable)
{
fs.WriteLine(string.Format("{0}: {1}", item.Key, item.Value.Item2));
}
}
其中\u cache
的定义如下:
static Dictionary<string, Tuple<bool, string, string>> _cache;
静态字典\u缓存;
我是否迭代此可枚举项两次?一次使用
Count()
和一次使用foreach
?是的,您迭代此可枚举项两次
测试这一点的简单方法是使用以下帮助器方法:
private static int count = 0;
public static IEnumerable<T> CountIterations<T>(IEnumerable<T> sequence)
{
count++;
//or some other debug type logging
Console.WriteLine("Iterated {0} times.", count);
foreach(var item in sequence)
yield return item;
}
private static int count=0;
公共静态IEnumerable CountIterations(IEnumerable序列)
{
计数++;
//或者其他一些调试类型的日志记录
WriteLine(“迭代了{0}次。”,count);
foreach(序列中的var项目)
收益回报项目;
}
是,为避免重复两次,请使用列表
您可以在初始迭代后打印计数。
另一种解决方案是保存循环中写入的文本,并在打印计数后打印
编辑更正:
using (FileStream fs = new FileStream(@"C:\bad_records.txt", FileMode.Create, FileAccess.Write))
{
var badEnumerable = _cache.Where(kvp => !kvp.Value.Item1);
int count = 0;
foreach (var item in badEnumerable)
{
count++;
Console.WriteLine(string.Format("{0}: {1}", item.Key, item.Value.Item2));
}
Console.WriteLine("==========");
Console.WriteLine(string.Format("BAD RECORDS ({0})", count));
}
您可以使用字典
\u缓存
作为KeyValuePair
的IEnumerable
其中方法已延迟执行。因此,您将它枚举两次:在
Count
和在foreach
中
您可以将其更改为:var badEnumerable=_cache.Where(kvp=>!kvp.Value.Item1.ToArray()代码>
和fs.WriteLine(string.Format(“坏记录({0})”,badEnumerable.Length)
是的,.Count()
和foreach
都会导致\u缓存
被枚举两次,并根据中的谓词进行验证,其中原因
至于这是否是一个问题,取决于许多因素:
\u cache
中的所有值是否都已存在于内存中,或者它正在查询底层源(如数据库)
查询的集合中有多少项,比较的成本是多少
可以安全地多次枚举源
例如,如果\u cache
中的值已经在内存中,并且谓词是简单的布尔属性比较,则枚举缓存两次可能更有效,不会增加额外的内存开销,而添加.ToList()
仍将导致两次枚举(一个\u缓存和一个列表)但是谓词检查只会发生一次(在.ToList()
调用中),并且foreach
将有更少的对象要枚举,但您将增加额外列表的额外内存开销
如果缓存来自数据库,则在.Where()
之后添加.ToList()
的内存开销几乎肯定比对数据库执行两次单独查询要好。简短的回答是肯定的
根据badEnumerable
的基本类型,它可能会被枚举两次。这是由于所谓的“.延迟执行意味着您的LINQ查询在foreach或For Each循环(MSDN)中对查询变量进行迭代之前”不会实际执行。您的foreach
语句显然是对变量的迭代,并且Enumerable.Count()
也执行迭代(在本例中)
但在某些情况下,这不会导致两次迭代。在这种情况下,调用.Count()
实际上引用了底层的.Count
属性,并且不枚举它
因为badEnumerable
是一个Dictionary
,也因为调用Enumerable.Where()
返回一个通用的IEnumerable
(一个不是ICollection
),您的特定案例不会遇到这种情况,将重复两次。是的,何处延迟了执行。为了得到明确的答案,我们需要知道缓存是什么类型的…@AakashM不知道。我们知道它被重复了两次。我们不知道这是否是一件非常糟糕的事情;重复它可能完全可以两次,或者这可能非常可怕,但我们可以100%肯定他重复了两次。我相信你自己的辩证能力可以理解这一点——这似乎是一个出于疑问的问题。@servy从提供的\u cache
示例中可以是任何东西,比如说,包括一个带有扩展方法的类,它取代了中的扩展方法de>可枚举的
,例如提供一个计数()
方法,该方法实际上没有枚举…没有任何解释,这不是一个真正有价值的答案。它似乎太简单了P@ashes999好的,解释实际上是在问题本身,Count
和foreach
每次迭代IEnumerable
。虽然我添加了一个sim卡,但没有太多要说的有多种方法可以更容易地观察到它。@Servy,这正是我所期望的。这些列表非常小(例如,最多15000个),因此这可能不是一个真正的目标问题,但事实上你已经完全证实了我的怀疑。非常感谢你的朋友!这个方法应该取代对.Count()的调用吗
?如果是这样,那么它只是因为badEnumerable
的类型才正确,并且这不能用于测试“does.Count()
枚举两次?”的一般情况,如果badEnumerable
实现了ICollection
,那么.Count()
不会产生两次迭代,但您的代码会。如果您投反对票,请至少留下一个简短的解释,说明为什么这个答案不正确。