简体   繁体   English

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

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

I have to flatted a 3d array in order to be serialized. 我必须将3d阵列弄平才能进行序列化。 Let's start with this: 让我们从这个开始:

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

which makes it like this (something like 1,2,3,4,...,24): 这样(类似于1,2,3,4,...,24):

在此处输入图片说明

So now I have this s/r 所以现在我有这个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;
}

which flattens the 3d matrix into a 1d array 将3d矩阵展平为1d数组

在此处输入图片说明

I am not smart enough to understand if the procedure is correct but let's go further. 我不够聪明,无法理解该程序是否正确,但让我们进一步。 I then Expand with the following s/r 然后,使用以下代码扩展

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

but the result is the following: 但是结果如下:

在此处输入图片说明

So nothing like 1,2,3,4,5....24 I know that the error might be a trivial one but try as I might I can't find it. 所以没有像1,2,3,4,5 .... 24这样的错误,我知道该错误可能是微不足道的,但是请尝试一下,因为我可能找不到它。 Thank in advance. 预先感谢。

Patrick 帕特里克


Thanks for helping all 3 solution were amazing and working but I chose the one more easily to understand and debug for me 感谢您帮助所有3个解决方案都很棒并且可以正常工作,但是我为我选择了一个更容易理解和调试的解决方案

With a help of Linq OfType<T>() , it's easy to have int[] from any multidimensional array: 借助Linq OfType<T>() ,很容易从任何多维数组中获取int[]

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

Demo: 演示:

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

Outcome: 结果:

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

We can use modulo arithmetics to Expand array back: 我们可以使用模算术将数组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;
}

Eg 例如

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

To flatten a multidimensional array just use Cast<T>().ToArray() . 展平多维数组,只需使用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));

Gives: 给出:

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

To expand use this: 扩展使用此:

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

Usage: 用法:

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

with helper method: 使用辅助方法:

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("}");
}

Gives: 给出:

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

I am assuming that you want to know what is the mistake in your code more than you want to know the quickest way to get to the answer. 我假设您想知道代码中的错误多于想要知道答案的最快方法。 Your index calculation is wrong. 您的索引计算错误。 You are calculating it like this: 您正在这样计算:

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

But you actually need to multiply the last term not just by rows1 but by rows0 too: 但实际上,您不仅需要将最后一项乘以row1,还应乘以row0:

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

Also, it makes sense to swap the order of dimensions that are iterated in for loops to get results in order. 同样,交换在for循环中迭代的维度顺序以按顺序获得结果也很有意义。 The final code for that would be: 最终的代码将是:

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

You could give this a go: 您可以尝试一下:

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

It worked fine for me. 对我来说很好。

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

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