Преобразовать список <double>в двойное число [n, 1] - PullRequest
2 голосов
/ 09 апреля 2020

Мне нужно преобразовать большой список длины n в двойной массив [n, 1]. Какой самый быстрый способ выполнить преобразование?

. Для дальнейшего использования в фоновом режиме необходимо указать Range.Value объекта Excel, для которого требуется двумерный массив.

Ответы [ 2 ]

4 голосов
/ 09 апреля 2020

Я пишу это при условии, что вы действительно хотите наиболее эффективный способ сделать это. Чрезвычайная производительность почти всегда сопровождается компромиссом, обычно читабельностью кода.

Я все еще могу существенно оптимизировать одну часть этого, как отмечается в комментариях, но я не хотел go за бортом, используя Dynami c методы при первом проходе.

const int TEST_SIZE = 100 * 1000;
//Test data setup
var list = new List<double>();
for (int i = 0; i < TEST_SIZE; i++)
    list.Add(i);
//Grab the list's underlying array, which is not public
//This can be made MUCH faster with dynamic methods if you want me to optimize
var underlying = (double[])typeof(List<double>)
    .GetField("_items", BindingFlags.NonPublic | BindingFlags.Instance)
    .GetValue(list);
//We need the actual length of the list because there can be extra space in the array
//Do NOT use "underlying.Length"
int underlyingLength = list.Count;
//Benchmark it
var sw = Stopwatch.StartNew();
var twodarray = new double[underlyingLength, 1];
Buffer.BlockCopy(underlying, 0, twodarray, 0, underlyingLength * sizeof(double));
var elapsed = sw.Elapsed;
Console.WriteLine($"Elapsed: {elapsed}");

Вывод:

Прошло: 00: 00: 00.0001998

Используемое оборудование:

AMD Ryzen 7 3800X @ 3,9 ГГц, 32 ГБ, оперативная память DDR4 3200

1 голос
/ 09 апреля 2020

Я думаю, это то, что вам нужно.

Эта операция займет не более нескольких миллисекунд даже на медленном ядре. Так зачем? Сколько раз вы будете делать это преобразование? Если миллионы раз, чем пытаться найти лучший подход. Но если вы делаете это, когда конечный пользователь нажимает кнопку ...

Критикуйте ответ, но, пожалуйста, предоставьте метрики, если речь идет об эффективности.

// Populate a List with 100.000 doubles
Random r = new Random();
List<double> dList = new List<double>();
int i = 0;
while (i++ < 100000) dList.Add(r.NextDouble());

// Convert to double[100000,1]
Stopwatch chrono = Stopwatch.StartNew();

// Conversion:
double[,] ddArray = new double[dList.Count, 1];
int dIndex = 0;
dList.ForEach((x) => ddArray[dIndex++, 0] = x);

Console.WriteLine("Completed in: {0}ms", chrono.Elapsed);

Выходы: (10 повторений) - Максимум: 2,6 мс

Completed in: 00:00:00.0020677ms
Completed in: 00:00:00.0026287ms
Completed in: 00:00:00.0013854ms
Completed in: 00:00:00.0010382ms
Completed in: 00:00:00.0019168ms
Completed in: 00:00:00.0011480ms
Completed in: 00:00:00.0011172ms
Completed in: 00:00:00.0013586ms
Completed in: 00:00:00.0017165ms
Completed in: 00:00:00.0010508ms

Редактировать 1.

double[,] ddArray = new double[dList.Count, 1];
foreach (double x in dList) ddArray[dIndex++, 0] = x;

кажется немного быстрее, но требует дополнительного тестирования:

Completed in: 00:00:00.0020318ms
Completed in: 00:00:00.0019077ms
Completed in: 00:00:00.0023162ms
Completed in: 00:00:00.0015881ms
Completed in: 00:00:00.0013692ms
Completed in: 00:00:00.0022482ms
Completed in: 00:00:00.0015960ms
Completed in: 00:00:00.0012306ms
Completed in: 00:00:00.0015039ms
Completed in: 00:00:00.0016553ms
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...