C# 如何将数组列表转换为多维数组

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/9774901/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-09 08:48:46  来源:igfitidea点击:

How to convert list of arrays into a multidimensional array

c#linqmultidimensional-arrayjagged-arrays

提问by Arne Lund

I need to convert the following collection into double[,]:

我需要将以下集合转换为 double[,]:

 var ret = new List<double[]>();

All the arrays in the list have the same length. The simplest approach, ret.ToArray(), produces double[][], which is not what I want. Of course, I can create a new array manually, and copy numbers over in a loop, but is there a more elegant way?

列表中的所有数组都具有相同的长度。最简单的方法,ret.ToArray()产生double[][],这不是我想要的。当然,我可以手动创建一个新数组,然后循环复制数字,但是有没有更优雅的方法?

Edit:my library is invoked from a different language, Mathematica, which has not been developed in .Net. I don't think that language can utilize jagged arrays. I do have to return a multidimensional array.

编辑:我的库是从另一种语言 Mathematica 调用的,该语言尚未在 .Net 中开发。我不认为该语言可以使用锯齿状数组。我必须返回一个多维数组。

采纳答案by Jon Skeet

I don't believe there's anything built into the framework to do this - even Array.Copyfails in this case. However, it's easy to write the code to do it by looping:

我不相信框架中内置了任何东西来做到这一点 -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;
    }

}

回答by Jodrell

If you are going to copy (I can't think of a better way)

如果你要复制(我想不出更好的方法)

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;


EDIT

编辑

I'm almost certain looping rather than using SelectManyand ToArrayis faster.

我几乎可以肯定循环而不是使用SelectMany并且ToArray速度更快。

I know when I've been skeeted.

我知道我什么时候被人盯上了。

回答by Marcin

You can do following as extension:

您可以执行以下操作作为扩展:

    /// <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;
    }

回答by Ethan Brown

There's no easy way to do this because in the situation you're describing, there's nothing stopping the double[]arrays in the list from being different sizes, which would be incompatible with a two-dimensional rectangular array. However, if you are in the position to guarantee the double[]arrays all have the same dimensionality, you can construct your two-dimensional array as follows:

没有简单的方法可以做到这一点,因为在您所描述的情况下,没有什么可以阻止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];
}

This will produce a run-time error if any of the double[]arrays in the list are shorter than the first one, and you will lose data if any of the arrays are bigger than the first one.

如果double[]列表中的任何数组比第一个短,这将产生运行时错误,如果任何数组大于第一个,您将丢失数据。

If you are really determined to store a jagged array in a rectangular array, you can use a "magic" value to indicate there is no value in that position. For example:

如果你真的决定在矩形数组中存储一个锯齿状数组,你可以使用一个“魔术”值来表示该位置没有值。例如:

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;
}

On an editorial note, I think this is a Very Bad Idea™; when you go to use the rectangular array, you have to check for Double.NaNall the time. Furthermore, what if you wanted to use Double.NaNas a legitimate value in the array? If you have a jagged array, you should just leave it as a jagged array.

在社论中,我认为这是一个非常糟糕的主意™;当你去使用矩形阵列时,你必须一直检查Double.NaN。此外,如果您想Double.NaN用作数组中的合法值怎么办?如果您有一个锯齿状数组,则应该将其保留为锯齿状数组。