如何在 C# 中将 0 放在多维数组的末尾
How to put the 0s at the end of my multidimensional arrays in C#
如何将 0 放在多维数组的末尾。我的数组大小为 4x5。
这些是我的价值观
4 23 1 0 9
0 6 0 77 9
0 23 0 0 66
0 38 65 2
预期结果:
4 23 1 9 6
77 9 23 66 38
65 2 0 0 0
0 0 0 0 0
我用这段代码试过了。我试图将非零数组移动到一个新的多维数组,然后用零填充其余数组,但我一直出现越界错误。
static void MoveZero(int[,] arrayNum)
{
int newArrayIndex = 0;
int newArrayIndex1 = 0;
int[,] newarrayNum=new int[4,5];
for (var outer = 0; outer < 4; outer++)
{
if(newArrayIndex1>=6){
newArrayIndex1=0;
}
if(newArrayIndex>=5){
newArrayIndex=0;
}
for (var inner = 0; inner < 5; inner++)
{
if(arrayNum[outer,inner]==0){
continue;
}
newarrayNum[newArrayIndex,newArrayIndex1] = arrayNum[outer,inner];
newArrayIndex++;
}
newArrayIndex1++;
}
Display(newarrayNum);
}
按照步骤进行
- 创建相同的空新数组。
- 扫描你的数组。
- 如果扫描时遇到 non-zero 值,则将其复制到新数组。
- 复制值后立即增加新数组的索引。
例子
给定的初始数组是
int[,] array = new int[,]
{
{ 4, 23, 1, 0, 9},
{ 0, 6, 0, 77, 9},
{ 0, 23, 0, 0, 66 },
{ 0, 38, 65, 2,0 }
};
代码为
int[,] array2 = new int[4, 5];
int i2 = 0;
int j2 = 0;
for (int i = 0; i < 4; i++)
{
for (int j = 0; j < 5; j++)
{
if (array[i, j] != 0)
{
array2[i2, j2] = array[i, j];
j2++;
if (j2 > 4)
{
j2 = 0;
i2++;
}
}
}
}
评论你的代码
您的总体做法是正确的。从您的代码中可以看出您正在扫描数组,并且每当您遇到 non-zero 值时,您都会将其复制到新数组。因此,您正在执行上面给出的步骤 1、2 和 3。但是你在错误的地方增加了新数组的索引。 newArrayIndex1
在外循环中,newArrayIndex
在内循环中。正确的时机是在将值复制到新数组之后。
因此,不合逻辑的算法构建(未遵循第 4 步)最终导致您犯了一个您已经遇到的错误。
对您的代码的一些观察和评论:
- 您(以及阅读您代码的任何人)都受益于简单但具有描述性的变量名称。这也有助于调试代码;特别是在 visually/manually 调试它时。
- 您在
MoveZero()
中多次使用值 4
和 5
MoveZero()
不知道输入数组的大小(行数和列数)`,但在您的代码中,假定大小已知
- 在原始数组中的每次迭代都会检查新数组中使用的索引。由于新数组的索引与原始数组的索引无关,因此在解释代码中的逻辑时这可能会造成混淆并引起噪音。
关于如何根据这些评论更改代码的建议:
- 引入简单的描述性变量名
arrayNum
--> array
。推理:您和您的代码都知道输入数组包含数字 (int
s),因为它是 int[,]
类型。此外,MoveZero()
中没有其他类型的数组(即您不需要区分整数数组和字符串数组)。尽可能保持简单。
outer
--> rowIndex
/row
。推理:当变量描述数组的维度时,更容易想象你的数组是如何迭代的(即在你的代码中随时检查哪个单元格)。 row
和 col
是相关词。
inner
--> colIndex
/col
。推理:与 outer
. 相同
newarrayNum
--> newArray
。推理:与 arrayNum
. 相同
newArrayIndex
--> newRowIndex
/newRow
。推理:与 outer
. 相同
newArrayIndex1
--> newColIndex
/newCol
。推理:与 outer
. 相同
- 为 魔法值创建变量
- 为什么使用
4
和 5
?他们的意思是什么?很明显,当我们有您的示例输入数组的上下文/您对具有 4 行和 5 列的输入数组的描述时。但是,对于任何只看到 MoveZero()
而 没有 的人来说,它是 没有 clear/implicit。 =165=]
- 定义
int rowCount = 4;
和 int colCount = 5;
并在适当的地方替换 4
和 5
的使用。
- 不假设数组大小
- 所有
MoveZero()
对输入数组的了解是它的类型是 int[,]
。大小是2x3
还是134x896
,它不知道;因此,不应做出任何规模假设。 计算输入数组的行数和列数,而不是假设它们是4
和5
。
- 对于two-dimensional数组,您可以通过检查第0个数组维度(
arrayNum.GetLength(0)
)的长度来查找行数,通过检查第1个数组的长度来查找列数维度 (arrayNum.GetLength(1)
).
- 上一步中
rowCount
和colCount
的实现应该进行调整。行数和列数不应是静态数字。
- 在适当的地方进行有效性检查
- 验证新数组中使用的索引是有效索引只需要在它们被使用的时候做。新数组的索引仅在填充新数组时使用;即在内部 for 循环中,在检查原始数组中的项目是否等于
0
. 之后
实施这些更改后,您的方法现在可能如下所示:
static void MoveZero(int[,] array)
{
int rows = array.GetLength(0);
int cols = array.GetLength(1);
int newRow = 0;
int newCol = 0;
int[,] newArray = new int[rows, cols];
for (var row = 0; row < rows; row++)
{
for (var col = 0; col < cols; col++)
{
if (array[row, col] == 0)
{
continue;
}
if (newCol > cols)
{
newCol = 0;
}
if (newRow > rows)
{
newRow = 0;
}
newArray[newRow, newCol] = array[row, col];
newRow++; // updating new row index
}
newCol++; // updating new col index
}
Display(newArray);
}
现在,您可能会注意到几件事:
- 每当您在新数组中填充一个单元格时,新行索引 就会递增。 新行索引 的递增意味着您在同一列中向下移动。因此,您正在 逐列 填充新数组,即使您正在 逐行 遍历原始数组。据我了解您的问题,您确实希望 逐行 .
填充新数组
- 每当您移动到原始数组中的下一行时(即紧接在外部
for
循环的新迭代之前),新列索引 都会递增。由于您不知道输入数组中 0
值的位置,因此您不能假设 row/col 索引的更改会在代码中的任何时候同时发生在原始数组和新数组中.
通过在新数组的填充前直接添加一个Console.WriteLine()
,
Console.WriteLine($"newArray[{newRow}, {newCol}] = array[{row}, {col}] = {array[row, col]}");
newArray[newRow, newCol] = array[row, col];
我得到以下控制台输出:
newArray[0, 0] = array[0, 0] = 4
newArray[1, 0] = array[0, 1] = 23
newArray[2, 0] = array[0, 2] = 1
newArray[3, 0] = array[0, 4] = 9
newArray[4, 1] = array[1, 1] = 6
Unhandled exception. System.IndexOutOfRangeException: Index was outside the bounds of the array.
考虑到新行索引的快速递增,我认为这就是产生越界错误的原因。
新实现(包括控制台输出)的示例 fiddle 是 here。希望对您有所帮助r 解决问题。
有关如何修改代码以使其工作的建议
- 在使用
newCol
值填充 newArray
后直接更新(即,直接在 newArray[newRow, newCol] = array[row, col];
之后)。但是:不是无条件地 增加 newCol
值(即 newCol++
),而是 将值更新为下一个有效列值 .我们可以通过使用 modulo 运算符来实现这一点,如下所示:
newCol = (newCol + 1) % cols;
- 在您的示例中,有效列值为 0--4(总列数为 5)。这意味着当
newCol == 4
并且我们希望更新值时,我们希望设置 newCol = 0
而不是 newCol = 5
。在模运算中,newCol + 1
是 被除数 ,总列数是 模数 。模运算的结果,即除法运算 (newCol + 1) / cols
的 余数 是 newCol
. 的适当新值
- 更新
newCol
值后直接更新newRow
值;但是 仅 如果 newCol == 0
(即仅当我们从最右边的列转到最左边的列时)。
- 实施这两个更改后,不再需要检查
newCol
和 newRow
值的有效性;可以删除这些检查。
MoveZero()
的最终实现可能如下所示:
static void MoveZero(int[,] array)
{
int rows = array.GetLength(0);
int cols = array.GetLength(1);
int[,] newArray = new int[rows, cols];
int newRow = 0;
int newCol = 0;
for (var row = 0; row < rows; row++)
{
for (var col = 0; col < cols; col++)
{
if (array[row, col] == 0)
{
continue;
}
newArray[newRow, newCol] = array[row, col];
newCol = (newCol + 1) % cols;
if (newCol == 0)
{
newRow++;
}
}
}
Display(newArray);
}
示例 fiddle here.
我想这就是你想要做的
static void Main(string[] args)
{
var mat1_1d = new int[] {
4, 23, 1, 0, 9,
0, 6, 0, 77, 9,
0, 23, 0, 0, 66,
0, 38, 65, 2};
var mat2_2d = Resize(mat1_1d, 4, 5);
Display(mat2_2d);
//4 23 1 0 9
//0 6 0 77 9
//0 23 0 0 66
//0 38 65 2 0
Console.WriteLine();
var mat3_2d = Pack(mat2_2d);
Display(mat3_2d);
// 4 23 1 9 6
//77 9 23 66 38
//65 2 0 0 0
// 0 0 0 0 0
}
具有以下定义的函数 Resize()
、Pack()
和 Display()
:
/// <summary>
/// Packs the specified matrix. This moves all zeros to the end
/// of the matrix.
/// </summary>
/// <param name="matrix">The input matrix.</param>
/// <returns>A packed matrix of the same size.</returns>
static T[,] Pack<T>(T[,] matrix)
{
int rows = matrix.GetLength(0);
int columns = matrix.GetLength(1);
// Create a flat array from the matrix for sorting
T[] flat = new T[matrix.Length];
Buffer.BlockCopy(matrix, 0, flat, 0, Buffer.ByteLength(matrix));
// Generate a sequence of keys in ascending order
var keys = Enumerable.Range(1, matrix.Length).ToArray();
// Modify key sequence to replace 0's with a large number
keys = keys.Zip(flat, (num, x) => !x.Equals(0) ? num : matrix.Length+1).ToArray();
// Sort values based on keys
Array.Sort(keys, flat);
// Convert back to 2D matrix
T[,] result = new T[rows, columns];
Buffer.BlockCopy(flat, 0, result, 0, Buffer.ByteLength(matrix));
return result;
}
使用辅助函数从数组生成二维矩阵
/// <summary>
/// Convert an array into a 2D matrix
/// </summary>
/// <param name="array">The input array.</param>
/// <param name="rows">The number rows requested.</param>
/// <param name="columns">The number of columns requested.</param>
/// <returns></returns>
static T[,] Resize<T>(T[] array, int rows, int columns)
{
int length = Math.Max(array.Length, rows * columns);
var flat = new T[length];
Buffer.BlockCopy(array, 0, flat, 0, Buffer.ByteLength(array));
T[,] result = new T[rows, columns];
Buffer.BlockCopy(flat, 0, result, 0, Buffer.ByteLength(array));
return result;
}
使用固定列绘制控制台矩阵
/// <summary>
/// Displays the specified matrix in fixed columns of width 4.
/// </summary>
/// <param name="matrix">The matrix to display.</param>
static void Display<T>(T[,] matrix)
{
int rows = matrix.GetLength(0);
int columns = matrix.GetLength(1);
const int width = 4;
for (int i = 0; i < rows; i++)
{
for (int j = 0; j < columns; j++)
{
Console.Write($"{matrix[i, j],width} ");
}
Console.WriteLine();
}
}
如何将 0 放在多维数组的末尾。我的数组大小为 4x5。
这些是我的价值观
4 23 1 0 9
0 6 0 77 9
0 23 0 0 66
0 38 65 2
预期结果:
4 23 1 9 6
77 9 23 66 38
65 2 0 0 0
0 0 0 0 0
我用这段代码试过了。我试图将非零数组移动到一个新的多维数组,然后用零填充其余数组,但我一直出现越界错误。
static void MoveZero(int[,] arrayNum)
{
int newArrayIndex = 0;
int newArrayIndex1 = 0;
int[,] newarrayNum=new int[4,5];
for (var outer = 0; outer < 4; outer++)
{
if(newArrayIndex1>=6){
newArrayIndex1=0;
}
if(newArrayIndex>=5){
newArrayIndex=0;
}
for (var inner = 0; inner < 5; inner++)
{
if(arrayNum[outer,inner]==0){
continue;
}
newarrayNum[newArrayIndex,newArrayIndex1] = arrayNum[outer,inner];
newArrayIndex++;
}
newArrayIndex1++;
}
Display(newarrayNum);
}
按照步骤进行
- 创建相同的空新数组。
- 扫描你的数组。
- 如果扫描时遇到 non-zero 值,则将其复制到新数组。
- 复制值后立即增加新数组的索引。
例子
给定的初始数组是
int[,] array = new int[,]
{
{ 4, 23, 1, 0, 9},
{ 0, 6, 0, 77, 9},
{ 0, 23, 0, 0, 66 },
{ 0, 38, 65, 2,0 }
};
代码为
int[,] array2 = new int[4, 5];
int i2 = 0;
int j2 = 0;
for (int i = 0; i < 4; i++)
{
for (int j = 0; j < 5; j++)
{
if (array[i, j] != 0)
{
array2[i2, j2] = array[i, j];
j2++;
if (j2 > 4)
{
j2 = 0;
i2++;
}
}
}
}
评论你的代码
您的总体做法是正确的。从您的代码中可以看出您正在扫描数组,并且每当您遇到 non-zero 值时,您都会将其复制到新数组。因此,您正在执行上面给出的步骤 1、2 和 3。但是你在错误的地方增加了新数组的索引。 newArrayIndex1
在外循环中,newArrayIndex
在内循环中。正确的时机是在将值复制到新数组之后。
因此,不合逻辑的算法构建(未遵循第 4 步)最终导致您犯了一个您已经遇到的错误。
对您的代码的一些观察和评论:
- 您(以及阅读您代码的任何人)都受益于简单但具有描述性的变量名称。这也有助于调试代码;特别是在 visually/manually 调试它时。
- 您在
MoveZero()
中多次使用值 MoveZero()
不知道输入数组的大小(行数和列数)`,但在您的代码中,假定大小已知- 在原始数组中的每次迭代都会检查新数组中使用的索引。由于新数组的索引与原始数组的索引无关,因此在解释代码中的逻辑时这可能会造成混淆并引起噪音。
4
和 5
关于如何根据这些评论更改代码的建议:
- 引入简单的描述性变量名
arrayNum
-->array
。推理:您和您的代码都知道输入数组包含数字 (int
s),因为它是int[,]
类型。此外,MoveZero()
中没有其他类型的数组(即您不需要区分整数数组和字符串数组)。尽可能保持简单。outer
-->rowIndex
/row
。推理:当变量描述数组的维度时,更容易想象你的数组是如何迭代的(即在你的代码中随时检查哪个单元格)。row
和col
是相关词。inner
-->colIndex
/col
。推理:与outer
. 相同
newarrayNum
-->newArray
。推理:与arrayNum
. 相同
newArrayIndex
-->newRowIndex
/newRow
。推理:与outer
. 相同
newArrayIndex1
-->newColIndex
/newCol
。推理:与outer
. 相同
- 为 魔法值创建变量
- 为什么使用
4
和5
?他们的意思是什么?很明显,当我们有您的示例输入数组的上下文/您对具有 4 行和 5 列的输入数组的描述时。但是,对于任何只看到MoveZero()
而 没有 的人来说,它是 没有 clear/implicit。 =165=] - 定义
int rowCount = 4;
和int colCount = 5;
并在适当的地方替换4
和5
的使用。
- 为什么使用
- 不假设数组大小
- 所有
MoveZero()
对输入数组的了解是它的类型是int[,]
。大小是2x3
还是134x896
,它不知道;因此,不应做出任何规模假设。 计算输入数组的行数和列数,而不是假设它们是4
和5
。 - 对于two-dimensional数组,您可以通过检查第0个数组维度(
arrayNum.GetLength(0)
)的长度来查找行数,通过检查第1个数组的长度来查找列数维度 (arrayNum.GetLength(1)
). - 上一步中
rowCount
和colCount
的实现应该进行调整。行数和列数不应是静态数字。
- 所有
- 在适当的地方进行有效性检查
- 验证新数组中使用的索引是有效索引只需要在它们被使用的时候做。新数组的索引仅在填充新数组时使用;即在内部 for 循环中,在检查原始数组中的项目是否等于
0
. 之后
- 验证新数组中使用的索引是有效索引只需要在它们被使用的时候做。新数组的索引仅在填充新数组时使用;即在内部 for 循环中,在检查原始数组中的项目是否等于
实施这些更改后,您的方法现在可能如下所示:
static void MoveZero(int[,] array)
{
int rows = array.GetLength(0);
int cols = array.GetLength(1);
int newRow = 0;
int newCol = 0;
int[,] newArray = new int[rows, cols];
for (var row = 0; row < rows; row++)
{
for (var col = 0; col < cols; col++)
{
if (array[row, col] == 0)
{
continue;
}
if (newCol > cols)
{
newCol = 0;
}
if (newRow > rows)
{
newRow = 0;
}
newArray[newRow, newCol] = array[row, col];
newRow++; // updating new row index
}
newCol++; // updating new col index
}
Display(newArray);
}
现在,您可能会注意到几件事:
- 每当您在新数组中填充一个单元格时,新行索引 就会递增。 新行索引 的递增意味着您在同一列中向下移动。因此,您正在 逐列 填充新数组,即使您正在 逐行 遍历原始数组。据我了解您的问题,您确实希望 逐行 . 填充新数组
- 每当您移动到原始数组中的下一行时(即紧接在外部
for
循环的新迭代之前),新列索引 都会递增。由于您不知道输入数组中0
值的位置,因此您不能假设 row/col 索引的更改会在代码中的任何时候同时发生在原始数组和新数组中.
通过在新数组的填充前直接添加一个Console.WriteLine()
,
Console.WriteLine($"newArray[{newRow}, {newCol}] = array[{row}, {col}] = {array[row, col]}");
newArray[newRow, newCol] = array[row, col];
我得到以下控制台输出:
newArray[0, 0] = array[0, 0] = 4
newArray[1, 0] = array[0, 1] = 23
newArray[2, 0] = array[0, 2] = 1
newArray[3, 0] = array[0, 4] = 9
newArray[4, 1] = array[1, 1] = 6
Unhandled exception. System.IndexOutOfRangeException: Index was outside the bounds of the array.
考虑到新行索引的快速递增,我认为这就是产生越界错误的原因。
新实现(包括控制台输出)的示例 fiddle 是 here。希望对您有所帮助r 解决问题。
有关如何修改代码以使其工作的建议
- 在使用
newCol
值填充newArray
后直接更新(即,直接在newArray[newRow, newCol] = array[row, col];
之后)。但是:不是无条件地 增加newCol
值(即newCol++
),而是 将值更新为下一个有效列值 .我们可以通过使用 modulo 运算符来实现这一点,如下所示:
newCol = (newCol + 1) % cols;
- 在您的示例中,有效列值为 0--4(总列数为 5)。这意味着当
newCol == 4
并且我们希望更新值时,我们希望设置newCol = 0
而不是newCol = 5
。在模运算中,newCol + 1
是 被除数 ,总列数是 模数 。模运算的结果,即除法运算(newCol + 1) / cols
的 余数 是newCol
. 的适当新值
- 在您的示例中,有效列值为 0--4(总列数为 5)。这意味着当
- 更新
newCol
值后直接更新newRow
值;但是 仅 如果newCol == 0
(即仅当我们从最右边的列转到最左边的列时)。 - 实施这两个更改后,不再需要检查
newCol
和newRow
值的有效性;可以删除这些检查。
MoveZero()
的最终实现可能如下所示:
static void MoveZero(int[,] array)
{
int rows = array.GetLength(0);
int cols = array.GetLength(1);
int[,] newArray = new int[rows, cols];
int newRow = 0;
int newCol = 0;
for (var row = 0; row < rows; row++)
{
for (var col = 0; col < cols; col++)
{
if (array[row, col] == 0)
{
continue;
}
newArray[newRow, newCol] = array[row, col];
newCol = (newCol + 1) % cols;
if (newCol == 0)
{
newRow++;
}
}
}
Display(newArray);
}
示例 fiddle here.
我想这就是你想要做的
static void Main(string[] args)
{
var mat1_1d = new int[] {
4, 23, 1, 0, 9,
0, 6, 0, 77, 9,
0, 23, 0, 0, 66,
0, 38, 65, 2};
var mat2_2d = Resize(mat1_1d, 4, 5);
Display(mat2_2d);
//4 23 1 0 9
//0 6 0 77 9
//0 23 0 0 66
//0 38 65 2 0
Console.WriteLine();
var mat3_2d = Pack(mat2_2d);
Display(mat3_2d);
// 4 23 1 9 6
//77 9 23 66 38
//65 2 0 0 0
// 0 0 0 0 0
}
具有以下定义的函数 Resize()
、Pack()
和 Display()
:
/// <summary>
/// Packs the specified matrix. This moves all zeros to the end
/// of the matrix.
/// </summary>
/// <param name="matrix">The input matrix.</param>
/// <returns>A packed matrix of the same size.</returns>
static T[,] Pack<T>(T[,] matrix)
{
int rows = matrix.GetLength(0);
int columns = matrix.GetLength(1);
// Create a flat array from the matrix for sorting
T[] flat = new T[matrix.Length];
Buffer.BlockCopy(matrix, 0, flat, 0, Buffer.ByteLength(matrix));
// Generate a sequence of keys in ascending order
var keys = Enumerable.Range(1, matrix.Length).ToArray();
// Modify key sequence to replace 0's with a large number
keys = keys.Zip(flat, (num, x) => !x.Equals(0) ? num : matrix.Length+1).ToArray();
// Sort values based on keys
Array.Sort(keys, flat);
// Convert back to 2D matrix
T[,] result = new T[rows, columns];
Buffer.BlockCopy(flat, 0, result, 0, Buffer.ByteLength(matrix));
return result;
}
使用辅助函数从数组生成二维矩阵
/// <summary>
/// Convert an array into a 2D matrix
/// </summary>
/// <param name="array">The input array.</param>
/// <param name="rows">The number rows requested.</param>
/// <param name="columns">The number of columns requested.</param>
/// <returns></returns>
static T[,] Resize<T>(T[] array, int rows, int columns)
{
int length = Math.Max(array.Length, rows * columns);
var flat = new T[length];
Buffer.BlockCopy(array, 0, flat, 0, Buffer.ByteLength(array));
T[,] result = new T[rows, columns];
Buffer.BlockCopy(flat, 0, result, 0, Buffer.ByteLength(array));
return result;
}
使用固定列绘制控制台矩阵
/// <summary>
/// Displays the specified matrix in fixed columns of width 4.
/// </summary>
/// <param name="matrix">The matrix to display.</param>
static void Display<T>(T[,] matrix)
{
int rows = matrix.GetLength(0);
int columns = matrix.GetLength(1);
const int width = 4;
for (int i = 0; i < rows; i++)
{
for (int j = 0; j < columns; j++)
{
Console.Write($"{matrix[i, j],width} ");
}
Console.WriteLine();
}
}