Правильность расстановки скобок (C#) – рефакторинг

Опубликовано Dec 11, 2012 в Массивы и строки, Рефакторинг и оптимизация | 3 коммент.

, , ,

Правильность расстановки скобок (C#) – рефакторинг

В предыдущем посте на эту тему уже приведено много решений.

Интересным оказалось последнее (от 11 декабря), основанное на использовании стека.

Вот его код.

public class Brace
    {
        public static bool Check(string checkString)
        {
            var braceStack = new Stack();
 
            foreach (var chr in checkString)
            {
                if (chr == '(' || chr == '{' || chr == '[')
                {
                    braceStack.Push(chr);
                    continue;
                }
 
                if (chr != ')' && chr != '}' && chr != ']') continue;
 
                char brace;
 
                if (braceStack.Count > 0)
                    brace = braceStack.Pop();
                else
                    return false;
 
                switch (brace)
                {
                    case '(':
                        if (chr != ')') return false;
                        break;
                    case '{':
                        if (chr != '}') return false;
                        break;
                    case '[':
                        if (chr != ']') return false;
                        break;
                }
            }
 
            return braceStack.Count == 0;
        }
    }

Общая оценка.  Идея использования структуры данных стек для этой задачи алгоритмически удачна и в целом код написан хорошо. Возникает вопрос: “Можно ли здесь что-то улучшить?” Вопрос, конечно, риторический, совершенству нет предела, но вот какие соображения могут иметь место по поводу подобных задач.

Что можно улучшить? Имеется явное  повторение кода через хардкод проверяемых символов. Хорошо, если это задачка с алгоритмом, который  вмещается на один экран. А если это промышленный код и разрабатывался какой-то длинный и сложный алгоритм с немалой стоимостью? При этом специальных символов, которые нужно расставлять в десятки мест по коду не три, а гораздо больше.  И все это нужно поддерживать для вызовов из многих мест, где возможны разные подмножества проверяемых символов на входе алгоритма. Стоит подумать, как от хардкода избавиться. Один из вариантов, например, такой.

public static bool CheckAllBraces(string checkString,
            char[] openBracesChars, char[] closeBracesChars)
        {
          var braceStack = new Stack();
 
          foreach (var chr in checkString)
          {
            if (Array.Exists(openBracesChars, element => element == chr))
            {
              braceStack.Push(chr);
              continue;
            }
 
            if (!Array.Exists(closeBracesChars, element => element == chr))
              continue;
 
            char brace;
 
            if (braceStack.Count > 0)
              brace = braceStack.Pop();
            else
              return false;
 
            if (Array.IndexOf(openBracesChars, brace) !=
                        Array.IndexOf(closeBracesChars, chr))
              return false;
          }
          return braceStack.Count == 0;
        }
    //ВЫЗОВ
     char[] openBracesChars  = {'(','[','{'};
     char[] closeBracesChars = { ')', ']', '}' };
 
     b = Brace.CheckAllBraces("((( ) ])( ))", openBracesChars, closeBracesChars);

Задача на собеседовании. Если подходить к задаче исходя из критериев собеседования, то второй вариант интереснее еще и потому, что кроме соображений, изложенных выше (они основные), в нем продемонстрировано использование некоторых более продвинутых средств, характерных именно для языка C#: знание класса Array его основных методов, а также простейший способ применения лямбда-выражений. Это как раз то, за что можно получить дополнительные баллы по владению базовым синтаксисом языка, по которому проходят собеседования.


Автор публикации: