Как упростить условие if, имеющее несколько случаев ИЛИ [закрыто]

У меня есть условие в C #, как показано ниже:

if( myString.Contains("UCK") OR
    myString.Contains("SAN") OR
    myString.Contains("AVB") OR
    myString.Contains("AVM") OR
    myString.Contains("SDS") OR
    myString.Contains("DWW") OR
    myString.Contains("WQP") OR
    myString.Contains("LHG") OR
  )
{
 mySecondString = "CATEGORY A";
}

else if( myString.Contains("UCT") OR
    myString.Contains("SAM") OR
    myString.Contains("AHJB") OR
    myString.Contains("AVR") OR
  )
{
 mySecondString = "CATEGORY B";
}

else if( myString.Contains("UKC") OR
    myString.Contains("SHZ") OR
    myString.Contains("EEB") OR
  )
{
 mySecondString = "CATEGORY C";
}

else  mySecondString = "CATEGORY D";

Я хочу сделать это более профессиональным. Какой лучший способ вы предлагаете?

Спасибо

 Blorgbeard13 июл. 2016 г., 00:02
Нет никакихOR в C # ты имеешь ввиду|| ?
 Matt Johnson-Pint13 июл. 2016 г., 00:05
Как выглядит входная строка? Это в согласованной форме, такой как список значений, разделенных запятыми? Или это просто случайный текст? Можете ли вы привести пример? Кроме того, это чувствителен к регистру? (Они похожи на коды аэропортов, так что я бы не догадался)
 tCoe13 июл. 2016 г., 00:08
создание списка <string>, вероятно, будет лучшим выбором, если вы не хотите ссылаться на базу данных.
 Bob Kaufman13 июл. 2016 г., 00:04
Этот список может измениться? Если это так, я бы создал таблицу в вашей базе данных, предполагая, что ваше приложение использует ее. В противном случае, я бы создалDictionary<string, string> гдеKey каждая строка, такая как "UCK", "SAN" и т. д. иValue это каждая категория. Это большемнение чемответ конечно, именно поэтому он здесь в комментариях, а не размещен как авторитетный ответ.
 Eray Balkanli13 июл. 2016 г., 00:12
да, я имею в виду || ...

Ответы на вопрос(5)

но применяется независимо от того, используете ли вы:

Если у вас есть такое долгое условие, вы должны изолировать его в своей собственной функции, например:

string GetCategory(string input)
{
    //all of your conditions
    return mySecondString;
}

Затем в методе, который раньше содержал это условие, вместо этого у вас есть вызов функции, например

var category = GetCategory(myString);

Это делает несколько вещей:

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

Еще одно предложение - использовать константы, как

const string AliensVersusBovines = "AVB";

Это мешает кому-то читать это:

myString.Contains("AVB")

и интересно, что такое "AVB", так как это не говорит само за себя. Если вы собираетесь использовать эту строку в нескольких классах (что кажется вероятным), то вы можете создать отдельный класс, который будет содержать все эти константы. Это предотвращает разбрасывание одного и того же строкового литерала по всему коду, что может стать проблемой обслуживания.

public class Codes
{
    public const string AliensVersusBovines = "AVB";
}

Таким образом, ваш код может читать

myString.Contains(Codes.AliensVersusBovines)

лучший подход заключается в использованииMap (на Java) илиDictionary в C #:

class MyExample {
    // declaring your static map (should be private static final)
    private static Dictionary<String, String> myPreciousMap = new HashMap<>();

    public MyExample() {
        String categoryA = "CATEGORY A";
        String categoryX = "CATEGORY X"; // you know, A, B, C, D etc
        myPreciousMap.Add("UCK", categoryA);
        myPreciousMap.Add("SAN", categoryA);
        myPreciousMap.Add("X", categoryX);
    }

    // using it
    public String getCategory(String myString) {
        // this returns exact match (which is recommended)
        // return myPreciousMap.GetValue(myString);

        // this is using the contains
        foreach( KeyValuePair<string, string> kvp in myPreciousMap) {
            if (myString.contains(kvp.getKey()) return kvp.getValue();
        }
        return "Some sort of Default";
    }
}

Таким образом, вы избегаете всех ifs и очень легко видите соответствующие значения и редактируете их.

 Beccari13 июл. 2016 г., 02:17
@KlitosKyriacou Это правда, что карта не подходит для соответствия «содержит», но небольшое изменение сделало бы эту работу. Суть в том, чтобы убрать эту кучу уродливых и трудных для понимания «если». Так что, если вам нужно выполнить итерацию по карте, используя параметр содержит (что просто), пусть будет так. И снова ИМХО, это гораздо лучше, чем использовать любую другую цепочку предложений "если"
 Klitos Kyriacou13 июл. 2016 г., 08:36
Действительно, с этим изменением код выполняет свою работу, и он более универсален, так как управляется таблицами: например, вы можете просто добавить другую категорию. Мое единственное оставшееся замечание заключается в том, что вы сейчас используете словарь просто как набор пар. Словарь содержит хеш-таблицу, которая вообще не используется. Однако, если вам нужна коллекция пар, словарь прост в использовании, даже если он не самый эффективный.
 Klitos Kyriacou13 июл. 2016 г., 00:45
Это не эквивалентно.myString может быть "xyzUCK123", и вы хотите, чтобы он отображался на "КАТЕГОРИЮ A", потому что этосодержит «ОАК».
 Beccari13 июл. 2016 г., 02:25
Просто отредактировал код в соответствии с примером. Еще раз, вопрос был «Как упростить условие if, имеющее несколько случаев ИЛИ»

Могли бы использоватьРегулярное выражение Я не лучший производитель регулярных выражений:

if (Regex.IsMatch(myString, "/(LHG)|(UCK)|(SAN)|(AVB)|(AVM)|(SDS)|(DWW)|(WQP)/")) {
    mySecondString = "CATEGORY A";
} else ...

Вот хорошее место для проверки регулярных выражений для C #

если вы просто хотите, оно было сделано быстро и грязно:

        if (new[] { "UCK", "SAN", "AVB", "AVM", "SDS", "DWW", "WQP", "LHG" }.Any(s => myString.Contains(s)))
        {
            mySecondString = "CATEGORY A";
        }

        else if (new[] { "UCT", "SAM", "AHJB", "AVR" }.Any(s => myString.Contains(s)))
        {
            mySecondString = "CATEGORY B";
        }

        else if (new[] { "UKC", "SHZ", "EEB" }.Any(s => myString.Contains(s)))
        {
            mySecondString = "CATEGORY C";
        }

        else
        {
            mySecondString = "CATEGORY D";
        }
 user647065513 июл. 2016 г., 00:32
И вот почему вы правильно прочитали вопрос: P. Как насчет отредактированного ответа?
 Mr Anderson13 июл. 2016 г., 00:26
Это будет соответствовать, только если массив содержит точное значение, основанное наObject.Equals() - отличный отString.Contains()
 Matthias13 июл. 2016 г., 00:26
Мм, это не эквивалентно. Не понизить хотя: P
 Mr Anderson13 июл. 2016 г., 00:35
Мне это нравится. Я забыл использоватьAny() в моем ответе. Ну что ж ;)
Решение Вопроса

Используйтеметод расширения:

public static bool ContainsAny(this string self, params string[] criteria)
{
    foreach (string s in criteria)
    {
        if (self.Contains(s))
        {
            return true;
        }
    }
    return false;
}

Назовите это так:

if (myString.ContainsAny("UCK", "SAN", "AVB", "AVM", "SDS", "DWW", "WQP", "LHG"))
{
    mySecondString = "CATEGORY A";
}

else if (myString.ContainsAny("UCT", "SAM", "AHJB", "AVR"))
{
    mySecondString = "CATEGORY B";
}

else if (myString.ContainsAny("UKC", "SHZ", "EEB"))
{
    mySecondString = "CATEGORY C";
}

else
{
    mySecondString = "CATEGORY D";
}

Ваш ответ на вопрос