C# flattening/expanding 一个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 数组
我不够聪明,无法理解程序是否正确,但让我们更进一步。
然后我用下面的 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;
}
但结果如下:
所以不像 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;
但实际上您不仅需要将最后一项乘以第 1 行,还需要乘以第 0 行:
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;
}
对我来说效果很好。
我必须展平 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 数组
我不够聪明,无法理解程序是否正确,但让我们更进一步。 然后我用下面的 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;
}
但结果如下:
所以不像 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;
但实际上您不仅需要将最后一项乘以第 1 行,还需要乘以第 0 行:
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;
}
对我来说效果很好。