我需要将以下集合转换为double [,]:
var ret = new List<double[]>();
列表中的所有数组都具有相同的长度。最简单的方法ret.ToArray()
会产生double [] [],这不是我想要的。当然,我可以手动创建一个新数组,并在循环中复制数字,但是有更优雅的方式吗?
编辑:我的图书馆是使用另一种语言Mathematica调用的,该语言尚未在.Net中开发。我不认为该语言可以利用锯齿状数组。我必须返回一个多维数组。
答案 0 :(得分:24)
我不相信框架中有任何内容可以做到这一点 - 即使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;
}
}
答案 1 :(得分:5)
您可以执行以下扩展名:
/// <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;
}
答案 2 :(得分:5)
没有简单的方法可以做到这一点,因为在你所描述的情况下,没有什么能阻止列表中的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 :(得分: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
更快。
我知道我什么时候受到了抨击。
答案 4 :(得分:0)
我正在寻找相反的要求,我需要将2维数组转换为数组数组。我需要这个是因为json本身不支持多维数组的序列化。
/// <summary>
/// converts a 2 dimensional array to an array of arrays
/// </summary>
/// <typeparam name="T">type of arays</typeparam>
/// <param name="src">2-dimensional array</param>
/// <returns>array of arrays of the same size the <paramref name="src"/></returns>
public static T[][] Convert2DArray<T>(this T[,] src)
{
// match input
if (src == null)
return null;
// get array dimensions
var height = src.GetLength(0);
var width = src.GetLength(1);
// create the new array
var tgt = new T[height][];
for (int i = 0; i < height; i++)
{
tgt[i] = new T[width];
for (int j = 0; j < width; j++)
tgt[i][j] = src[i, j];
}
// return it
return tgt;
}
这是3维版本:
/// <summary>
/// converts a 3 dimensional array to an array of arrays
/// </summary>
/// <typeparam name="T">type of arays</typeparam>
/// <param name="src">3-dimensional array</param>
/// <returns>array of arrays of the same size the <paramref name="src"/></returns>
public static TDest[][][] Convert3DArray<TSrc, TDest>(this TSrc[,,] src, Func<TSrc, TDest> converter)
{
// match input
if (src == null)
return null;
if (converter is null)
throw new ArgumentNullException(nameof(converter));
// get array dimensions
var iLen = src.GetLength(0);
var jLen = src.GetLength(1);
var kLen = src.GetLength(2);
// create the new array
var tgt = new TDest[iLen][][];
for (int i = 0; i < iLen; i++)
{
tgt[i] = new TDest[jLen][];
for (int j = 0; j < jLen; j++)
{
tgt[i][j] = new TDest[kLen];
for (int k = 0; k < kLen; k++)
tgt[i][j][k] = converter(src[i, j, k]);
}
}
// return it
return tgt;
}
为了获得更多乐趣,此功能可用于同时删除尺寸(3D-> 2D)
/// <summary>
/// converts a 3 dimensional array to an array of arrays (2D)
/// </summary>
/// <typeparam name="T">type of arays</typeparam>
/// <param name="src">3-dimensional array</param>
/// <param name="converter">a function to convert the 3rd dimension into a new type (e.g. concatenated string)</param>
/// <returns>array of arrays of the same size the <paramref name="src"/></returns>
public static TDest[][] Convert3DTo2DArray<TSrc, TDest>(this TSrc[,,] src, Func<IEnumerable<TSrc>, TDest> converter)
{
// match input
if (src == null)
return null;
if (converter is null)
throw new ArgumentNullException(nameof(converter));
// get array dimensions
var iLen = src.GetLength(0);
var jLen = src.GetLength(1);
var kLen = src.GetLength(2);
// create the new array
var tgt = new TDest[iLen][];
for (int i = 0; i < iLen; i++)
{
tgt[i] = new TDest[jLen];
for (int j = 0; j < jLen; j++)
{
tgt[i][j] = converter(GetEnumerableFor3rdDimension(src, i, j, kLen));
}
}
// return it
return tgt;
}
private static IEnumerable<T> GetEnumerableFor3rdDimension<T>(T[,,] src, int i, int j, int kLen)
{
for (int k = 0; k < kLen; k++)
yield return src[i, j, k];
}