C#:根据用户输入创建字符串数组,然后,如果无法将其解析为int数组,请重试输入

时间:2018-11-24 20:17:21

标签: c# arrays user-input tryparse

我一直在尝试使用C#制作矩阵控制台应用程序,但是在检查用户输入的可行性时,我一直很努力。这是代码:

//INPUT OF VALUES INTO MATRIX A BY ROWS
int ValuesCounter = 2; //index for new arrays created on fail.
string[] valuesValuesCounter = Console.ReadLine().Split(' '); //read user input into string array
int[] valuescheckValuesCounter = new int[valuesValuesCounter.Length]; //test array to check if user input can be parsed into int
for (int i = 0; i <= valuesValuesCounter.Length; i++) // loop for checking parseability of individual array items
{
    while(!int.TryParse(valuesValuesCounter[i], out valuescheckValuesCounter[i])) //same
    {
        /*if it can't be parsed, create new array and try again*/
        ValuesCounter += 2;
        Console.WriteLine("Wrong values! Please try again!");
        valuesValuesCounter = Console.ReadLine().Split(' ');
        valuescheckValuesCounter = new int[valuesValuesCounter.Length];
    }
}

我怀疑这是非常有效的。我尝试使用ArrayList代替,因为您只能删除其中的值,但是无法拆分,因此我不知道如何使其工作。有什么更好的方法呢?
还尝试进行我自己的研究,但没有找到任何解决方案(也许它在那里,我只是因为没有看到它而愚蠢,我不知道)。

How to delete an array in c#?
Convert 2D string array into 2D int array (Multidimensional Arrays)
C# arraylist user input
int.TryParse out into an object array(这似乎很接近,但我看不到有任何东西可以重试输入以防无法解析)。

因此,您已经拥有了它。我很傻,所以如果这个问题看起来很愚蠢,那是因为问这个问题的那个愚蠢的人。

2 个答案:

答案 0 :(得分:2)

首先,使用户体验尽可能好。一次输入矩阵容易出错,使用户的生活更轻松,并逐步进行操作。

第二,制作执行简单任务的小型方法;如果出现新的要求,它们就更容易推理,更容易编写,更容易调试和更容易修改。不要让方法做太多事情,它只会给您带来头痛,并且会花费不必要的调试时间。如果您正在学习,请不要担心似乎正在分解为看似荒谬的简单任务,您不会后悔。永远记住,您可以想象到的最复杂的问题总是可以解决较小更简单的问题。

因此,您首先需要的是一种提示用户输入有效整数的方法,因此请尝试以下操作:

private static int GetIntegerFromUser(string prompt)
{
    int value;
    Console.Write($"{prompt}: ");

    while (!int.TryParse(Console.ReadLine(), out value))
    {
        Console.WriteLine("That is not a valid value. Please try again.");
        Console.Write($"{prompt}: ");
    }

    return value;
}

看看效果如何?这种方法在生活中有一个目标。让用户输入有效的整数。不必介意整数是什么,它不在乎,那不是它的工作,这种方法将不断询问用户,直到实现其生活目标为止。

好的,接下来是什么?填写矩阵时,我们需要知道:

  1. 行数
  2. 列数

好吧,让我们写一些方法来获取这些信息:

private static (int Rows, int Columns) GetMatrixSize()
{
    var rows = GetIntegerFromUser("Please enter number of rows");
    var columns = GetIntegerFromUser("Please enter number of columns");
    return (rows, columns);
}

然后

private static int[,] GetMatrixValues(int rows, int columns)
{
    var matrix = new int[rows, columns];

    for (var row = 0; row < rows; row++)
    {
        for (var column = 0; column < columns; column++)
        {
            matrix[row, column] =
               GetIntegerFromUser($"Enter matrix value [{row}, {column}]");
        }
    }
}

现在您应该意识到为什么制作能够完成简单任务的小型方法是一个好主意的原因。因为机会真的很好,所以您将可以重用它们,一旦您知道该方法正确运行,它便会在任何地方正确运行。

好吧,我们已经有了所有需要的东西,现在只需将它们放在一起即可。

public static int[,] GetMatrixFromUser()
{
    var size = GetMatrixSize();
    return GetMatrixValues(size.Rows, size.Columns);
}

那读起来有多容易?

所以,我们完成了!真?好吧我们根本没有价值验证,这可能是一个问题。如果有人决定输入负数行会怎样?好的,没问题,让我们建立一个确保值在有效范围内的方法:

private static bool IsInRange(int value, 
                              int lowerInclusiveBound,
                              int upperExclusiveBound,
                              string messageOnFailedValidation)
{
    if (value >= lowerInclusiveBound &&
        value < upperExclusiveBound)
        return true;

    Console.WriteLine(messageOnFailedValidation);
    return false;
}

现在,由于我们使用了可以很好地定义任务的小型方法,因此可以轻松地对我们的GetMatrixSize方法进行一点修改来添加新的需求:

private static (int Rows, int Columns) GetMatrixSize()
{
    int rows, columns;

    do
    {
        rows = GetIntegerFromUser("Please enter number of rows");
        columns = GetIntegerFromUser("Please enter number of columns");
    } while (!IsInRange(rows,
                        1,
                        int.MaxValue,
                        "Number of rows must be equal or greater than one.") |
             !IsInRange(columns,
                        1,
                        int.MaxValue,
                        "Number of columns must be equal or greater than one."));

    return (rows, columns);
}

是的,现在我们完成了...

差不多!最后一件事。另一个好习惯是确保您所相信的事实是真实的。您认为GetMatrixValues内部的真实情况是什么?您认为rowscolumns将具有有效值。但是您的信念纯粹基于信念,您没有检查这是否正确。

但是等等...我已经签入GetMatrixSize,对吗?是的,但是您如何保证以后不会从其他某种方法调用GetMatrixValues?可重用性还记得吗?

在这里您可以走两条路。如果值无效或可以断言这些值实际上有效,则可以引发异常。因为该方法是私有的,并且值无效,所以可能意味着在调用堆栈中存在错误,因此,更好的选择是声明您的真相:

private static int[,] GetMatrixValues(int rows, int columns)
{
    Debug.Assert(rows > 0 && columns > 0);
    var matrix = ...
}

还有其他关于信仰的真理吗?谁在确保upperExclusiveBound中的lowerInclusiveBoundIsInRange确实有意义?是否有人阻止您拨打以下电话:IsInRange(10, 100, -100, ...)?这样的调用可能是代码中其他地方的错误,通过使这类错误更容易发现,可以使您的生活更轻松。再次声明您的真相:

private static bool IsInRange(int value, 
                              int lowerInclusiveBound,
                              int upperExclusiveBound,
                              string messageOnFailedValidation)
{  
    Debug.Assert(upperExclusiveBound > lowerInclusiveBound);

    if ...
}  

如果您应该检查prompt中的GetIntegerFromUsermessageOnFailedValidation中的IsInRange不是空字符串也不是空字符串,那么这也是一个很好的例子。< / p>

是的,现在我们真的完成了。

答案 1 :(得分:0)

在for循环内不需要while循环。只需检查每个项目的有效性和中断,如果遇到无效的字符串,当然,如果所有的字符串都有效(循环将结束),并且i将等于数组的长度:

bool success = false;
do
{
     int i = 0;
     string[] valuesValuesCounter = Console.ReadLine().Split(' ');
     int[] valuescheckValuesCounter = new int[valuesValuesCounter.Length];
     for (int i = 0; i <= valuesValuesCounter.Length; i++)
        if(!int.TryParse(valuesValuesCounter[i], out valuescheckValuesCounter[i]) break;
     success = i == valuesValuesCounter.Length;
}while(!success);

另一种方法是使用Linq:

do
{
    int i = 0;
    string[] valuesValuesCounter = Console.ReadLine().Split(' ');
    int[] valuescheckValuesCounter = new int[valuesValuesCounter.Length];
    success = valuesValuesCounter.All(x => int.TryParse(x, out valuescheckValuesCounter[i++]);
}while(!success);