gpt4 book ai didi

c# - 遍历序列然后调用 Count() 或在开始时创建一个列表然后调用 Count

转载 作者:太空宇宙 更新时间:2023-11-03 10:40:39 25 4
gpt4 key购买 nike

我使用的语言是c#

假设我们要遍历名为 customers 的序列的元素,该序列是名为 Customer 的虚构类型的对象序列。在代码方面,我们有以下内容:

IEnumerable<Customer> customers = module.GetCustomers();

其中 module 是服务层的类,通过其中一种方法,我们可以检索所有客户。也就是说,customers 元素的迭代将是:

foreach(var customer in customers)
{

}

现在让我们在遍历 customers 的元素后获取客户数量。这可以像下面这样完成:

int numberOfCustomers = customers.Count();

我现在的顾虑/问题如下:

我们使用 Count() 方法再次遍历 customers 的元素。但是,如果我们已经创建了该对象的内存集合,例如调用方法 ToList():

List<Customer> customers = module.GetCustomers()
.ToList();

我们将使用 customers 列表的 Count 属性在 O(1) 中获得客户数量。

为了找出这两个选项中最好的一个,我编写了一个简单的控制台应用程序,并使用 StopWatch 类来分析它们。但是,我没有得出明确的结果。

这两个选项中哪个是最好的?

更新

我运行了以下控制台应用程序:

class Program
{
static void Main(string[] args)
{
IEnumerable<int> numbers = Enumerable.Range(0, 1000);

Stopwatch stopwatch = new Stopwatch();

stopwatch.Start();

foreach (var number in numbers)
Console.WriteLine(number);


Console.WriteLine(numbers.Count());

stopwatch.Stop();

// I got 175ms
Console.WriteLine(stopwatch.ElapsedMilliseconds);

Console.ReadKey();

stopwatch.Restart();

List<int> numbers2 = numbers.ToList();

foreach (var number in numbers2)
Console.WriteLine(number);

Console.WriteLine(numbers2.Count);

stopwatch.Stop();

// I got 86ms
Console.WriteLine(stopwatch.ElapsedMilliseconds);

Console.ReadKey();
}
}

然后我运行了这个:

class Program
{
static void Main(string[] args)
{
IEnumerable<int> numbers = Enumerable.Range(0, 1000);

Stopwatch stopwatch = new Stopwatch();

stopwatch.Start();

List<int> numbers2 = numbers.ToList();

foreach (var number in numbers2)
Console.WriteLine(number);

Console.WriteLine(numbers2.Count);

stopwatch.Stop();

// I got 167ms
Console.WriteLine(stopwatch.ElapsedMilliseconds);

Console.ReadKey();

stopwatch.Restart();

foreach (var number in numbers)
Console.WriteLine(number);


Console.WriteLine(numbers.Count());

stopwatch.Stop();

// I got 104ms
Console.WriteLine(stopwatch.ElapsedMilliseconds);

Console.ReadKey();
}
}

最佳答案

我通常更喜欢让我的存储库方法返回一个 IReadOnlyCollection<> ,这有助于调用者知道他们可以安全地对其进行多次迭代:

IReadOnlyCollection<Customer> customers = module.GetCustomers();

如果我做不到,并且我知道我将多次迭代我得到的内容,我通常会使用 .ToList() 来确保我正在处理一个 in-内存收集:

var customers = module.GetCustomers().ToList();

在 customers 已经是内存集合的情况下,这会通过创建列表增加一些开销,但它有助于避免通过执行诸如从数据库中多次检索数据之类的操作而产生大量开销的风险次。

您的基准测试存在缺陷有几个原因,但最大的原因之一是它使用了 Console.WriteLine() , 它执行 I/O 操作。该操作将花费远远超过迭代集合和计算结果的总和。事实上,在 Console.WriteLine() 中花费的时间量方差将超过您正在测试的代码中的差异。

但这实际上很好地说明了我的观点——I/O 操作比 CPU 和内存操作花费的时间长得多,因此通常值得添加 .ToList() ,这可能会增加运行时间微秒,以避免添加可能增加毫秒的 I/O 操作的可能性最小。

关于c# - 遍历序列然后调用 Count() 或在开始时创建一个列表然后调用 Count,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25455766/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com