Попробуйте заменить «код» на «pre». Предварительный тег в HTML отмечает текст как предварительно отформатированный, и все строки и пробелы будут отображаться точно так же, как вы их набираете.
Преобразовать double[, ]
в List<double>
? Если вы ищете однострочник, то здесь
double[,] d = new double[,]
{
{1.0, 2.0},
{11.0, 22.0},
{111.0, 222.0},
{1111.0, 2222.0},
{11111.0, 22222.0}
};
List<double> lst = d.Cast<double>().ToList()
Что ж, вы можете сделать так, чтобы он использовал «блитовую» копию, хотя это означает создание дополнительной копии: (
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
реализован как нативный метод, который, как я ожидаю , будет использовать чрезвычайно эффективное копирование после проверки. List<T> constructor
, который принимает IEnumerable<T>
, оптимизирован для случая, когда он реализует IList<T>
, как это делает double[]
. Он создаст резервный массив нужного размера и попросит его скопировать себя в этот массив. Надеюсь, что будет использовать Buffer.BlockCopy
или что-то подобное тоже.
Вот краткий тест трех подходов (для цикла, 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 и блок-копия занимают примерно одно и то же время.
Петля for
- самый быстрый способ.
Вы можете сделать это с помощью LINQ, но это будет медленнее. И хотя вы сами не пишете цикл, под капотом все еще есть цикл.
arr.SelectMany(x=>x).ToList()
. T[,]
вы можете просто сделать arr.ToList()
, поскольку IEnumerable<T>
из T[,]
возвращает все элементы в 2D-массиве. S> Похоже, что 2D-массив реализует только IEnumerable
, но не IEnumerable<T>
, так что вам нужно вставить Cast<double>
как еще один предложенный кодер. Это сделает его еще медленнее из-за бокса. Единственное, что может сделать код быстрее, чем простой цикл, - это вычислить количество элементов и построить список с правильной емкостью, поэтому его не нужно увеличивать.
Если ваш массив прямоугольный, вы можете получить размер как width*height
, с неровными массивами это может быть сложнее.
int width=1000;
int height=3000;
double[,] arr=new double[width,height];
List<double> list=new List<double>(width*height);
int size1=arr.GetLength(1);
int size0=arr.GetLength(0);
for(int i=0;i<size0;i++)
{
for(int j=0;j<size1;j++)
list.Add(arr[i,j]);
}
Теоретически может быть возможно использовать частное отражение и небезопасный код, чтобы сделать его немного быстрее, делая сырую копию памяти. Но я настоятельно советую против этого.