C #: создание массива строк из пользовательского ввода, затем, если он не может быть проанализирован в массиве int, повторная попытка ввода - PullRequest
0 голосов
/ 24 ноября 2018

Я пытался создать матричное консольное приложение на 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, потому что вы можете просто удалить значения в нем, но его нельзя разделить, поэтому я не знаю, как заставить его работать.Что может быть лучше для этого?
Также пытался провести собственное исследование, но не нашел решения (может быть, оно есть, и я просто глуп, что не вижу его, не знаю).

Как удалить массив в c #?
Преобразование массива 2D-строк в 2D-массив int (многомерных массивов)
C # пользовательский ввод массива
int.TryParse в массив объектов (это выглядит довольно близко, но я не вижу там ничего, чтобы повторить ввод в случае, если он не может быть проанализирован).

Так вот, у вас есть это.Я довольно тупой, поэтому, если этот вопрос кажется глупым, это потому, что тот, кто задает его, глуп.

Ответы [ 2 ]

0 голосов
/ 25 ноября 2018

Прежде всего, сделайте пользовательский опыт как можно лучше.Одновременный ввод матрицы может привести к ошибкам, упростить жизнь пользователя и сделать его шаг за шагом.

Во-вторых, создавать небольшие методы, выполняющие простые задачи;их легче рассуждать, легче писать, легче отлаживать и легче модифицировать, если появляются новые требования.Не заставляйте методы делать слишком много, это принесет вам только головную боль и больше времени на отладку, чем необходимо.Если вы учитесь, не волнуйтесь, если вам кажется, что вы ломаетесь от, казалось бы, нелепо простых задач, вы об этом не пожалеете.Всегда помните, что самые сложные проблемы, которые вы можете себе представить, всегда решаются путем решения более мелких и простых задач.

Итак, первое, что вам нужно, - это метод, который запрашивает у пользователя действительное целое число, поэтому давайте попробуем это:

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. Количество столбцов
  3. Значения

OkДавайте напишем несколько методов, которые выбирают именно это:

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?Вы верите, что rows и columns будут иметь допустимые значения.Но ваша вера основана исключительно на вере, вы не проверяете, верно ли это.

Но подождите ... Я уже зарегистрировался в GetMatrixSize верно?Да, но какая у вас гарантия, что GetMatrixValues не будет вызываться из какого-либо другого метода позже?Многоразовость помнишь?

Здесь вы можете пойти двумя путями.Вы можете выдать исключение, если значения недопустимы, или вы можете утверждать, что значения действительно действительны.Поскольку этот метод является закрытым и наличие недопустимых значений, вероятно, означает ошибку где-то в стеке вызовов, лучшим вариантом здесь является утверждение ваших истин:

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

Какие-либо другие истины только по вере?Кто следит за тем, чтобы upperExclusiveBound и lowerInclusiveBound в IsInRange действительно имели смысл?Вам кто-то мешает сделать следующий звонок: IsInRange(10, 100, -100, ...)?Подобный вызов, вероятно, является ошибкой где-то еще в вашем коде, упростит вашу жизнь, упрощая обнаружение таких ошибок.Опять же, отстаивайте свои истины:

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

    if ...
}  

Хороший случай также может быть сделан в отношении того, следует ли проверять, что prompt в GetIntegerFromUser и messageOnFailedValidation в IsInRange не являются пустыми или нулевыми строкамии т.д.

Да, теперь мы действительно закончили.

0 голосов
/ 24 ноября 2018

Вам не нужен цикл while внутри цикла for.просто проверьте каждый элемент на правильность и разрыв, если вы встретите недопустимую строку, конечно, если все были действительны (цикл завершится) и 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);
...