好吧,你可以让它使用“blit”类型的副本,尽管这确实意味着制作一个额外的副本:(
double[] tmp = new double[array.GetLength(0) * array.GetLength(1)];
Buffer.BlockCopy(array, 0, tmp, 0, tmp.Length * sizeof(double));
List<double> list = new List<double>(tmp);
当然,如果您对一维数组感到满意,请忽略最后一行 :)
Buffer.BlockCopy 是作为本机方法实现的,我希望 在验证后使用极其高效的复制。接受IEnumerable<T> 的List<T> constructor 针对实现IList<T> 的情况进行了优化,就像double[] 一样。它将创建一个大小合适的后备数组,并要求它将自己复制到该数组中。希望这将使用Buffer.BlockCopy 或类似的东西。
以下是三种方法(for 循环、Cast<double>().ToList() 和 Buffer.BlockCopy)的快速基准测试:
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
class Program
{
static void Main(string[] args)
{
double[,] source = new double[1000, 1000];
int iterations = 1000;
Stopwatch sw = Stopwatch.StartNew();
for (int i = 0; i < iterations; i++)
{
UsingCast(source);
}
sw.Stop();
Console.WriteLine("LINQ: {0}", sw.ElapsedMilliseconds);
GC.Collect();
GC.WaitForPendingFinalizers();
sw = Stopwatch.StartNew();
for (int i = 0; i < iterations; i++)
{
UsingForLoop(source);
}
sw.Stop();
Console.WriteLine("For loop: {0}", sw.ElapsedMilliseconds);
GC.Collect();
GC.WaitForPendingFinalizers();
sw = Stopwatch.StartNew();
for (int i = 0; i < iterations; i++)
{
UsingBlockCopy(source);
}
sw.Stop();
Console.WriteLine("Block copy: {0}", sw.ElapsedMilliseconds);
}
static List<double> UsingCast(double[,] array)
{
return array.Cast<double>().ToList();
}
static List<double> UsingForLoop(double[,] array)
{
int width = array.GetLength(0);
int height = array.GetLength(1);
List<double> ret = new List<double>(width * height);
for (int i = 0; i < width; i++)
{
for (int j = 0; j < height; j++)
{
ret.Add(array[i, j]);
}
}
return ret;
}
static List<double> UsingBlockCopy(double[,] array)
{
double[] tmp = new double[array.GetLength(0) * array.GetLength(1)];
Buffer.BlockCopy(array, 0, tmp, 0, tmp.Length * sizeof(double));
List<double> list = new List<double>(tmp);
return list;
}
}
结果(以毫秒为单位的时间);
LINQ: 253463
For loop: 9563
Block copy: 8697
编辑:将 for 循环更改为在每次迭代时调用 array.GetLength(),for 循环和块复制大约需要相同的时间。