Как преобразовать список массивов в многомерный массив
Мне нужно преобразовать следующую коллекцию в double [,]:
var ret = new List<double[]>();
Все массивы в списке имеют одинаковую длину. Простейший подход ret.ToArray()
дает double [] [], чего я не хочу. Конечно, я могу создать новый массив вручную и скопировать числа в цикле, но есть ли более элегантный способ?
Изменить: моя библиотека вызывается с другого языка Mathematica, который не был разработан в .NET. Я не думаю, что язык может использовать зубчатые массивы. Мне нужно вернуть многомерный массив.
Ответы
Ответ 1
Я не верю, что что-то встроенное в инфраструктуру для этого - даже Array.Copy
не удается в этом случае. Тем не менее, легко написать код, чтобы сделать это путем циклизации:
using System;
using System.Collections.Generic;
class Test
{
static void Main()
{
List<int[]> list = new List<int[]>
{
new[] { 1, 2, 3 },
new[] { 4, 5, 6 },
};
int[,] array = CreateRectangularArray(list);
foreach (int x in array)
{
Console.WriteLine(x); // 1, 2, 3, 4, 5, 6
}
Console.WriteLine(array[1, 2]); // 6
}
static T[,] CreateRectangularArray<T>(IList<T[]> arrays)
{
// TODO: Validation and special-casing for arrays.Count == 0
int minorLength = arrays[0].Length;
T[,] ret = new T[arrays.Count, minorLength];
for (int i = 0; i < arrays.Count; i++)
{
var array = arrays[i];
if (array.Length != minorLength)
{
throw new ArgumentException
("All arrays must be the same length");
}
for (int j = 0; j < minorLength; j++)
{
ret[i, j] = array[j];
}
}
return ret;
}
}
Ответ 2
Нет простого способа сделать это, потому что в описываемой ситуации нет ничего, что останавливало бы массивы double[]
в списке от разных размеров, что было бы несовместимо с двумерным прямоугольным массивом. Однако, если вы в состоянии гарантировать, что массивы double[]
имеют одинаковую размерность, вы можете построить свой двумерный массив следующим образом:
var arr = new double[ret.Count(),ret[0].Count()];
for( int i=0; i<ret.Count(); i++ ) {
for( int j=0; j<ret[i].Count(); j++ )
arr[i,j] = ret[i][j];
}
Это приведет к ошибке во время выполнения, если любой из массивов double[]
в списке короче первого, и вы потеряете данные, если какой-либо из массивов больше первого.
Если вы действительно настроены хранить зубчатый массив в прямоугольном массиве, вы можете использовать "магическое" значение, чтобы указать, что в этой позиции нет значения. Например:
var arr = new double[ret.Count(),ret.Max(x=>x.Count())];
for( int i=0; i<ret.Count(); i++ ) {
for( int j=0; j<arr.GetLength(1); j++ )
arr[i,j] = j<ret[i].Count() ? ret[i][j] : Double.NaN;
}
В редакционной заметке я думаю, что это очень плохая идея и торговля;; когда вы идете использовать прямоугольный массив, вы должны постоянно проверять Double.NaN
. Кроме того, что, если вы хотите использовать Double.NaN
как законное значение в массиве? Если у вас есть зубчатый массив, вы должны просто оставить его как зубчатый массив.
Ответ 3
Вы можете сделать следующее как расширение:
/// <summary>
/// Conerts source to 2D array.
/// </summary>
/// <typeparam name="T">
/// The type of item that must exist in the source.
/// </typeparam>
/// <param name="source">
/// The source to convert.
/// </param>
/// <exception cref="ArgumentNullException">
/// Thrown if source is null.
/// </exception>
/// <returns>
/// The 2D array of source items.
/// </returns>
public static T[,] To2DArray<T>(this IList<IList<T>> source)
{
if (source == null)
{
throw new ArgumentNullException("source");
}
int max = source.Select(l => l).Max(l => l.Count());
var result = new T[source.Count, max];
for (int i = 0; i < source.Count; i++)
{
for (int j = 0; j < source[i].Count(); j++)
{
result[i, j] = source[i][j];
}
}
return result;
}
Ответ 4
Если вы собираетесь копировать (я не могу придумать лучшего способа)
var width = ret[0].length;
var length = ret.Count;
var newResult = new double[width, length]
Buffer.BlockCopy(ret.SelectMany(r => r).ToArray(),
0,
newResult,
0,
length * width);
return newResult;
ИЗМЕНИТЬ
Я почти уверен в том, что вместо цикла SelectMany
и ToArray
выполняется более быстрый цикл.
Я знаю, когда я был в восторге.