gpt4 book ai didi

c# - C# 中数组/列表的子集迭代器,没有 yield

转载 作者:行者123 更新时间:2023-11-28 06:26:32 25 4
gpt4 key购买 nike

一个存储 std::vector<int> 的类在内部可以使用子集索引轻松公开子集迭代器,如下所示:

开始:

return _data.begin() + _subset_begin;

结束:

return _data.begin() + _subset_end;

在 C# 中是否有一种有效的方法来执行此操作?我最初基于 yield 的实现非常缓慢。

for(int i = _subset_begin; i < _subset_end; ++i)
{
yield return _data[i];
}

如何有效地解决这个问题?

我知道这并不完全相同,因为 C++ 使用迭代器作为返回类型,而 C# 使用 IEnum;但这些是每种语言的约定...

最佳答案

如果您使用的是 Linq,那么使用原始数组还是包装数组实际上差别不大。

为了对此进行测试,我编写了以下程序:

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;

namespace Demo
{
public static class Program
{
private static void Main()
{
var sw = new Stopwatch();

int[] array = new int[1000000];

int loops = 100;

for (int trial = 0; trial < 4; ++trial)
{
sw.Restart();

for (int i = 0; i < loops; ++i)
subsetViaArraySegment(array, 0, array.Length).Sum();

Console.WriteLine("subsetViaArraySegment() took " + sw.Elapsed);
sw.Restart();

for (int i = 0; i < loops; ++i)
subsetViaYield(array, 0, array.Length).Sum();

Console.WriteLine("subsetViaYield() took " + sw.Elapsed);
sw.Restart();

for (int i = 0; i < loops; ++i)
array.Sum();

Console.WriteLine("Simple Sum() took " + sw.Elapsed);
sw.Restart();

for (int i = 0; i < loops; ++i)
{
int total = 0;

for (int j = 0, n = array.Length; j < n; ++j)
{
unchecked
{
total += array[j];
}
}
}

Console.WriteLine("Inline code took " + sw.Elapsed);
Console.WriteLine("");
}
}

private static IEnumerable<int> subsetViaYield(int[] source, int start, int count)
{
for (int i = start, n = start + count; i < n; ++i)
yield return source[i];
}

private static IEnumerable<int> subsetViaArraySegment(int[] source, int start, int count)
{
return new ArraySegment<int>(source, start, count);
}
}
}

它测试使用 Linq 使用 ArraySegment、yield 实现和原始数组本身对大型数组中的所有整数求和需要多长时间。它还在根本不使用 Linq 的情况下进行内联计算。

在 Windows 8.1 上运行 x64 RELEASE 构建的结果如下:

subsetViaArraySegment() took 00:00:00.6924651
subsetViaYield() took 00:00:00.9207855
Simple Sum() took 00:00:00.9876048
Inline code took 00:00:00.0884620

subsetViaArraySegment() took 00:00:01.0222854
subsetViaYield() took 00:00:00.9309415
Simple Sum() took 00:00:01.0031804
Inline code took 00:00:00.0890534

subsetViaArraySegment() took 00:00:01.0146586
subsetViaYield() took 00:00:00.9129277
Simple Sum() took 00:00:00.9842326
Inline code took 00:00:00.0890593

subsetViaArraySegment() took 00:00:01.0306027
subsetViaYield() took 00:00:00.9353762
Simple Sum() took 00:00:00.9902355
Inline code took 00:00:00.0879321

请注意 Linq 方法如何花费相似的时间 - 而内联代码要快很多倍。

因此,如果您确实需要最快的代码,则不应使用 Linq。相反,您可以使用 ArraySegment 来包装数组,然后编写使用数组段定义的子集的代码。

例如,计算整数数组段之和的函数可能如下所示:

public static long Sum(ArraySegment<int> arraySegment)
{
long total = 0;
var array = arraySegment.Array;

for (int i = arraySegment.Offset, n = i + arraySegment.Count; i < n; ++i)
total += array[i];

return total;
}

关于c# - C# 中数组/列表的子集迭代器,没有 yield,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28432158/

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