繁体   English   中英

C#将3D矩阵展平/扩展为锯齿状数组

[英]C# flattening/expanding a 3D matrix into a jagged array

我必须将3d阵列弄平才能进行序列化。 让我们从这个开始:

int[,,] array3D = new int[,,] { 
            { { 1, 2 }, { 3, 4 }, {5,6 }, {7,8 } },
            { { 9, 10}, { 11, 12},{ 13,14} , {15,16 }},
            { { 17, 18}, { 19, 20},{ 21,22}, {23,24 } }
        };

这样(类似于1,2,3,4,...,24):

在此处输入图片说明

所以现在我有这个S / R

public static T[] Flatten<T>(T[,,] arr)
{
    int rows0 = arr.GetLength(0);
    int rows1 = arr.GetLength(1);
    int rows2 = arr.GetLength(2);
    T[] arrFlattened = new T[rows0 * rows1* rows2];

    int i, j, k;
    for (k = 0; k < rows2; k++)
    {
        for (j = 0; j < rows1; j++)
        {
            for (i = 0; i < rows0; i++)
            {
                var test = arr[i, j, k];
                int index = i + j * rows0 + k * rows1;
                arrFlattened[index] = test;
            }
        }
    }
    return arrFlattened;
}

将3d矩阵展平为1d数组

在此处输入图片说明

我不够聪明,无法理解该程序是否正确,但让我们进一步。 然后,使用以下代码扩展

public static T[,,] Expand<T>(T[] arr, int rows0, int rows1)
{
    int length = arr.GetLength(0);
    int rows2 = length / rows0 / rows1;

    T[,,] arrExpanded = new T[rows0, rows1, rows2];
    for (int k = 0; k < rows2; k++)
    {
        for (int j = 0; j < rows1; j++)
        {
            for (int i = 0; i < rows0; i++)
            {
                T test = arr[i + j * rows0 + k * rows1];
                arrExpanded[i, j, k] = test;
            }
        }
    }
    return arrExpanded;
}

但是结果如下:

在此处输入图片说明

所以没有像1,2,3,4,5 .... 24这样的错误,我知道该错误可能是微不足道的,但是请尝试一下,因为我可能找不到它。 预先感谢。

帕特里克


感谢您帮助所有3个解决方案都很棒并且可以正常工作,但是我为我选择了一个更容易理解和调试的解决方案

借助Linq OfType<T>() ,很容易从任何多维数组中获取int[]

var result = source.OfType<int>().ToArray();

演示:

using System.Linq;

...

int[,,] array3D = new int[,,] {
  { {  1,  2}, {  3,  4}, {  5,  6}, { 7,  8 } },
  { {  9, 10}, { 11, 12}, { 13, 14}, {15, 16 } },
  { { 17, 18}, { 19, 20}, { 21, 22}, {23, 24 } },
};

var result = array3D.OfType<int>().ToArray();

Console.Write(string.Join(", ", result)); 

结果:

1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24

我们可以使用模算术将数组Expand回:

private static T[,,] Expand<T>(T[] value, int length1, int length2, int length3) {
  T[,,] result = new T[length1, length2, length3];

  for (int i = 0; i < value.Length; ++i) {
    int r = i / (length3 * length2);
    int c = i /  length3 % length2;
    int h = i %  length3;

    result[r, c, h] = value[i];
  }

  return result;
}

例如

int[,,] back = Expand(result, 3, 4, 2);

展平多维数组,只需使用Cast<T>().ToArray()

var d3 = new int[,,]
{
    { { 1, 2 }, { 3, 4 }, {5,6 }, {7,8 } },
    { { 9, 10}, { 11, 12},{ 13,14} , {15,16 }},
    { { 17, 18}, { 19, 20},{ 21,22}, {23,24 } }
};
var d1 = d3.Cast<int>().ToArray();
Console.WriteLine(string.Join(" ", d1));

给出:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24

扩展使用此:

static int[,,] Expand(int[] array, int size2, int size3)
{
    var size = new[] { array.Length / size2 / size3, size2, size3 };
    var res = Array.CreateInstance(typeof(int), size);
    for (var i = 0; i < array.Length; i++)
        res.SetValue(array[i], GetMultidimensionalIndex(i, size));

    return (int[,,])res;
}

static int[] GetMultidimensionalIndex(int index, int[] size)
{
    var factors = size.Select((item, i) => size.Skip(i).Aggregate((a, b) => a * b)).ToArray();
    var factorsHelper = factors.Zip(factors.Skip(1).Append(1), (Current, Next) => new { Current, Next }).ToArray();
    return factorsHelper.Select(item => index % item.Current / item.Next).ToArray();
}

用法:

var d3 = new int[,,]
{
    { { 1, 2 }, { 3, 4 }, {5,6 }, {7,8 } },
    { { 9, 10}, { 11, 12},{ 13,14} , {15,16 }},
    { { 17, 18}, { 19, 20},{ 21,22}, {23,24 } }
};
Console.WriteLine("Original:");
Print3DArray(d3);

var flat = d3.Cast<int>().ToArray();
Console.WriteLine("Flat:");
Console.WriteLine(string.Join(" ", flat));

var expanded = Expand(flat, d3.GetLength(1), d3.GetLength(2));
Console.WriteLine("Expanded:");
Print3DArray(expanded);

使用辅助方法:

static void Print3DArray(int[,,] array)
{
    Console.WriteLine("{");
    for (int i = 0; i < array.GetLength(0); i++)
    {
        Console.Write("    {");
        for (int j = 0; j < array.GetLength(1); j++)
        {
            Console.Write(" {");
            for (int k = 0; k < array.GetLength(2); k++)
            {
                Console.Write($" {array[i, j, k]}");
            }
            Console.Write(" }");
        }
        Console.WriteLine(" }");
    }
    Console.WriteLine("}");
}

给出:

Original:
{
    { { 1 2 } { 3 4 } { 5 6 } { 7 8 } }
    { { 9 10 } { 11 12 } { 13 14 } { 15 16 } }
    { { 17 18 } { 19 20 } { 21 22 } { 23 24 } }
}
Flat:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
Expanded:
{
    { { 1 2 } { 3 4 } { 5 6 } { 7 8 } }
    { { 9 10 } { 11 12 } { 13 14 } { 15 16 } }
    { { 17 18 } { 19 20 } { 21 22 } { 23 24 } }
}

我假设您想知道代码中的错误多于想要知道答案的最快方法。 您的索引计算错误。 您正在这样计算:

int index = i + j * rows0 + k * rows1;

但实际上,您不仅需要将最后一项乘以row1,还应乘以row0:

int index = i + j * rows0 + k * rows1 * rows0;

同样,交换在for循环中迭代的维度顺序以按顺序获得结果也很有意义。 最终的代码将是:

    public static T[] Flatten<T>(T[,,] arr)
    {
        int rows0 = arr.GetLength(0);
        int rows1 = arr.GetLength(1);
        int rows2 = arr.GetLength(2);
        T[] arrFlattened = new T[rows0 * rows1* rows2];

        int i, j, k;
        for (k = 0; k < rows0; k++)
        {
            for (j = 0; j < rows1; j++)
            {
                for (i = 0; i < rows2; i++)
                {
                    var test = arr[k, j, i];
                    int index = i + j * rows2 + k * rows1 * rows2;
                    arrFlattened[index] = test;
                }
            }
        }
        return arrFlattened;
    }

    public static T[,,] Expand<T>(T[] arr, int rows0, int rows1)
    {
        int length = arr.GetLength(0);
        int rows2 = length / rows0 / rows1;

        T[,,] arrExpanded = new T[rows0, rows1, rows2];
        int i, j, k;
        for (k = 0; k < rows0; k++)
        {
            for (j = 0; j < rows1; j++)
            {
                for (i = 0; i < rows2; i++)
                {
                    T test = arr[i + j * rows2 + k * rows1 * rows2];
                    arrExpanded[k, j, i] = test;
                }
            }
        }
        return arrExpanded;
    }

您可以尝试一下:

void Main()
{
    int[,,] array3D = new int[,,]
    {
        { { 1, 2 }, { 3, 4 }, {5,6 }, {7,8 } },
        { { 9, 10}, { 11, 12},{ 13,14} , {15,16 }},
        { { 17, 18}, { 19, 20},{ 21,22}, {23,24 } }
    };

    var flattened = array3D.Cast<int>().ToArray();

    var restored = Expand(flattened, 3, 4);
}

public static T[,,] Expand<T>(T[] arr, int rows0, int rows1)
{
    int length = arr.GetLength(0);
    int rows2 = length / rows0 / rows1;
    int x = 0;

    T[,,] arrExpanded = new T[rows0, rows1, rows2];
    for (int i = 0; i < rows0; i++)
    {
        for (int j = 0; j < rows1; j++)
        {
            for (int k = 0; k < rows2; k++)
            {
                T test = arr[x++];
                arrExpanded[i, j, k] = test;
            }
        }
    }
    return arrExpanded;
}

对我来说很好。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM